simplify web section list
This commit is contained in:
		
							parent
							
								
									3cb6ddd7f9
								
							
						
					
					
						commit
						35a4b377f8
					
				
					 8 changed files with 60 additions and 100 deletions
				
			
		|  | @ -26,8 +26,8 @@ import * as Animatable from 'react-native-animatable'; | ||||||
| import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests'; | import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests'; | ||||||
| 
 | 
 | ||||||
| type Props = { | type Props = { | ||||||
|   status?: Exclude<REQUEST_STATUS, REQUEST_STATUS.SUCCESS>; |   status?: REQUEST_STATUS; | ||||||
|   code?: Exclude<REQUEST_CODES, REQUEST_CODES.SUCCESS>; |   code?: REQUEST_CODES; | ||||||
|   icon?: string; |   icon?: string; | ||||||
|   message?: string; |   message?: string; | ||||||
|   loading?: boolean; |   loading?: boolean; | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ import { useRequestLogic } from '../../utils/customHooks'; | ||||||
| import { useFocusEffect } from '@react-navigation/native'; | import { useFocusEffect } from '@react-navigation/native'; | ||||||
| import BasicLoadingScreen from './BasicLoadingScreen'; | import BasicLoadingScreen from './BasicLoadingScreen'; | ||||||
| import i18n from 'i18n-js'; | import i18n from 'i18n-js'; | ||||||
| import { REQUEST_STATUS } from '../../utils/Requests'; | import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests'; | ||||||
| 
 | 
 | ||||||
| export type RequestScreenProps<T> = { | export type RequestScreenProps<T> = { | ||||||
|   request: () => Promise<T>; |   request: () => Promise<T>; | ||||||
|  | @ -13,7 +13,7 @@ export type RequestScreenProps<T> = { | ||||||
|     loading: boolean, |     loading: boolean, | ||||||
|     refreshData: (newRequest?: () => Promise<T>) => void, |     refreshData: (newRequest?: () => Promise<T>) => void, | ||||||
|     status: REQUEST_STATUS, |     status: REQUEST_STATUS, | ||||||
|     code: number | undefined |     code?: REQUEST_CODES | ||||||
|   ) => React.ReactElement; |   ) => React.ReactElement; | ||||||
|   cache?: T; |   cache?: T; | ||||||
|   onCacheUpdate?: (newCache: T) => void; |   onCacheUpdate?: (newCache: T) => void; | ||||||
|  |  | ||||||
|  | @ -21,22 +21,19 @@ import React, { useState } from 'react'; | ||||||
| import i18n from 'i18n-js'; | import i18n from 'i18n-js'; | ||||||
| import { Snackbar } from 'react-native-paper'; | import { Snackbar } from 'react-native-paper'; | ||||||
| import { | import { | ||||||
|   NativeScrollEvent, |  | ||||||
|   NativeSyntheticEvent, |  | ||||||
|   RefreshControl, |   RefreshControl, | ||||||
|   SectionListData, |   SectionListData, | ||||||
|   SectionListRenderItemInfo, |   SectionListProps, | ||||||
|   StyleSheet, |   StyleSheet, | ||||||
|   View, |   View, | ||||||
| } from 'react-native'; | } from 'react-native'; | ||||||
| import * as Animatable from 'react-native-animatable'; |  | ||||||
| import ErrorView from './ErrorView'; | import ErrorView from './ErrorView'; | ||||||
| import BasicLoadingScreen from './BasicLoadingScreen'; |  | ||||||
| import { TAB_BAR_HEIGHT } from '../Tabbar/CustomTabBar'; | import { TAB_BAR_HEIGHT } from '../Tabbar/CustomTabBar'; | ||||||
| import { ERROR_TYPE } from '../../utils/WebData'; |  | ||||||
| import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList'; | import CollapsibleSectionList from '../Collapsible/CollapsibleSectionList'; | ||||||
| import GENERAL_STYLES from '../../constants/Styles'; | import GENERAL_STYLES from '../../constants/Styles'; | ||||||
| import RequestScreen from './RequestScreen'; | import RequestScreen, { RequestScreenProps } from './RequestScreen'; | ||||||
|  | import { CollapsibleComponentPropsType } from '../Collapsible/CollapsibleComponent'; | ||||||
|  | import { REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests'; | ||||||
| 
 | 
 | ||||||
| export type SectionListDataType<ItemT> = Array<{ | export type SectionListDataType<ItemT> = Array<{ | ||||||
|   title: string; |   title: string; | ||||||
|  | @ -45,20 +42,27 @@ export type SectionListDataType<ItemT> = Array<{ | ||||||
|   keyExtractor?: (data: ItemT) => string; |   keyExtractor?: (data: ItemT) => string; | ||||||
| }>; | }>; | ||||||
| 
 | 
 | ||||||
| type Props<ItemT, RawData> = { | type Props<ItemT, RawData> = Omit< | ||||||
|   request: () => Promise<RawData>; |   CollapsibleComponentPropsType, | ||||||
|   refreshOnFocus: boolean; |   'children' | 'paddedProps' | ||||||
|   renderItem: (data: SectionListRenderItemInfo<ItemT>) => React.ReactNode; | > & | ||||||
|  |   Omit< | ||||||
|  |     RequestScreenProps<RawData>, | ||||||
|  |     | 'render' | ||||||
|  |     | 'showLoading' | ||||||
|  |     | 'showError' | ||||||
|  |     | 'refresh' | ||||||
|  |     | 'onFinish' | ||||||
|  |     | 'onMajorError' | ||||||
|  |   > & | ||||||
|  |   Omit< | ||||||
|  |     SectionListProps<ItemT>, | ||||||
|  |     'sections' | 'getItemLayout' | 'ListHeaderComponent' | 'ListEmptyComponent' | ||||||
|  |   > & { | ||||||
|     createDataset: ( |     createDataset: ( | ||||||
|       data: RawData | undefined, |       data: RawData | undefined, | ||||||
|       isLoading: boolean |       isLoading: boolean | ||||||
|     ) => SectionListDataType<ItemT>; |     ) => SectionListDataType<ItemT>; | ||||||
| 
 |  | ||||||
|   onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void; |  | ||||||
|   showError?: boolean; |  | ||||||
|   itemHeight?: number | null; |  | ||||||
|   autoRefreshTime?: number; |  | ||||||
|   updateData?: number | string; |  | ||||||
|     renderListHeaderComponent?: ( |     renderListHeaderComponent?: ( | ||||||
|       data?: RawData |       data?: RawData | ||||||
|     ) => React.ComponentType<any> | React.ReactElement | null; |     ) => React.ComponentType<any> | React.ReactElement | null; | ||||||
|  | @ -66,9 +70,7 @@ type Props<ItemT, RawData> = { | ||||||
|       data: { section: SectionListData<ItemT> }, |       data: { section: SectionListData<ItemT> }, | ||||||
|       isLoading: boolean |       isLoading: boolean | ||||||
|     ) => React.ReactElement | null; |     ) => React.ReactElement | null; | ||||||
|   stickyHeader?: boolean; |     itemHeight?: number | null; | ||||||
|   cache?: RawData; |  | ||||||
|   onCacheUpdate?: (newCache: RawData) => void; |  | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| const styles = StyleSheet.create({ | const styles = StyleSheet.create({ | ||||||
|  | @ -100,48 +102,12 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) { | ||||||
|     }; |     }; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const getRenderSectionHeader = ( |  | ||||||
|     data: { section: SectionListData<ItemT> }, |  | ||||||
|     loading: boolean |  | ||||||
|   ) => { |  | ||||||
|     const { renderSectionHeader } = props; |  | ||||||
|     if (renderSectionHeader) { |  | ||||||
|       return ( |  | ||||||
|         <Animatable.View |  | ||||||
|           animation={'fadeInUp'} |  | ||||||
|           duration={500} |  | ||||||
|           useNativeDriver={true} |  | ||||||
|         > |  | ||||||
|           {renderSectionHeader(data, loading)} |  | ||||||
|         </Animatable.View> |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     return null; |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const getRenderItem = (data: SectionListRenderItemInfo<ItemT>) => { |  | ||||||
|     const { renderItem } = props; |  | ||||||
|     return ( |  | ||||||
|       <Animatable.View |  | ||||||
|         animation={'fadeInUp'} |  | ||||||
|         duration={500} |  | ||||||
|         useNativeDriver={true} |  | ||||||
|       > |  | ||||||
|         {renderItem(data)} |  | ||||||
|       </Animatable.View> |  | ||||||
|     ); |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => { |  | ||||||
|     if (props.onScroll) { |  | ||||||
|       props.onScroll(event); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const render = ( |   const render = ( | ||||||
|     data: RawData | undefined, |     data: RawData | undefined, | ||||||
|     loading: boolean, |     loading: boolean, | ||||||
|     refreshData: (newRequest?: () => Promise<RawData>) => void |     refreshData: (newRequest?: () => Promise<RawData>) => void, | ||||||
|  |     status: REQUEST_STATUS, | ||||||
|  |     code?: REQUEST_CODES | ||||||
|   ) => { |   ) => { | ||||||
|     const { itemHeight } = props; |     const { itemHeight } = props; | ||||||
|     const dataset = props.createDataset(data, loading); |     const dataset = props.createDataset(data, loading); | ||||||
|  | @ -150,8 +116,8 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) { | ||||||
|     } |     } | ||||||
|     return ( |     return ( | ||||||
|       <CollapsibleSectionList |       <CollapsibleSectionList | ||||||
|  |         {...props} | ||||||
|         sections={dataset} |         sections={dataset} | ||||||
|         extraData={props.updateData} |  | ||||||
|         paddedProps={(paddingTop) => ({ |         paddedProps={(paddingTop) => ({ | ||||||
|           refreshControl: ( |           refreshControl: ( | ||||||
|             <RefreshControl |             <RefreshControl | ||||||
|  | @ -161,9 +127,7 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) { | ||||||
|             /> |             /> | ||||||
|           ), |           ), | ||||||
|         })} |         })} | ||||||
|         renderSectionHeader={(info) => getRenderSectionHeader(info, loading)} |         renderItem={props.renderItem} | ||||||
|         renderItem={getRenderItem} |  | ||||||
|         stickySectionHeadersEnabled={props.stickyHeader} |  | ||||||
|         style={styles.container} |         style={styles.container} | ||||||
|         ListHeaderComponent={ |         ListHeaderComponent={ | ||||||
|           props.renderListHeaderComponent != null |           props.renderListHeaderComponent != null | ||||||
|  | @ -171,11 +135,10 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) { | ||||||
|             : null |             : null | ||||||
|         } |         } | ||||||
|         ListEmptyComponent={ |         ListEmptyComponent={ | ||||||
|           loading ? ( |           loading ? undefined : ( | ||||||
|             <BasicLoadingScreen /> |  | ||||||
|           ) : ( |  | ||||||
|             <ErrorView |             <ErrorView | ||||||
|               status={ERROR_TYPE.CONNECTION_ERROR} |               status={status} | ||||||
|  |               code={code} | ||||||
|               button={{ |               button={{ | ||||||
|                 icon: 'refresh', |                 icon: 'refresh', | ||||||
|                 text: i18n.t('general.retry'), |                 text: i18n.t('general.retry'), | ||||||
|  | @ -187,8 +150,6 @@ function WebSectionList<ItemT, RawData>(props: Props<ItemT, RawData>) { | ||||||
|         getItemLayout={ |         getItemLayout={ | ||||||
|           itemHeight ? (d, i) => getItemLayout(itemHeight, d, i) : undefined |           itemHeight ? (d, i) => getItemLayout(itemHeight, d, i) : undefined | ||||||
|         } |         } | ||||||
|         onScroll={onScroll} |  | ||||||
|         hasTab={true} |  | ||||||
|       /> |       /> | ||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ import { | ||||||
|   StyleSheet, |   StyleSheet, | ||||||
| } from 'react-native'; | } from 'react-native'; | ||||||
| import i18n from 'i18n-js'; | import i18n from 'i18n-js'; | ||||||
| import { ActivityIndicator, Headline, withTheme } from 'react-native-paper'; | import { Headline, withTheme } from 'react-native-paper'; | ||||||
| import { CommonActions } from '@react-navigation/native'; | import { CommonActions } from '@react-navigation/native'; | ||||||
| import { StackNavigationProp } from '@react-navigation/stack'; | import { StackNavigationProp } from '@react-navigation/stack'; | ||||||
| import * as Animatable from 'react-native-animatable'; | import * as Animatable from 'react-native-animatable'; | ||||||
|  | @ -315,11 +315,11 @@ class HomeScreen extends React.Component<PropsType, StateType> { | ||||||
|    */ |    */ | ||||||
|   getRenderItem = ({ item }: { item: FeedItemType }) => this.getFeedItem(item); |   getRenderItem = ({ item }: { item: FeedItemType }) => this.getFeedItem(item); | ||||||
| 
 | 
 | ||||||
|   getRenderSectionHeader = ( |   getRenderSectionHeader = (data: { | ||||||
|     data: { section: SectionListData<FeedItemType> }, |     section: SectionListData<FeedItemType>; | ||||||
|     isLoading: boolean |   }) => { | ||||||
|   ) => { |  | ||||||
|     const { props } = this; |     const { props } = this; | ||||||
|  |     const icon = data.section.icon; | ||||||
|     if (data.section.data.length > 0) { |     if (data.section.data.length > 0) { | ||||||
|       return ( |       return ( | ||||||
|         <Headline style={styles.sectionHeader}>{data.section.title}</Headline> |         <Headline style={styles.sectionHeader}>{data.section.title}</Headline> | ||||||
|  | @ -335,16 +335,14 @@ class HomeScreen extends React.Component<PropsType, StateType> { | ||||||
|         > |         > | ||||||
|           {data.section.title} |           {data.section.title} | ||||||
|         </Headline> |         </Headline> | ||||||
|         {isLoading ? ( |         {icon ? ( | ||||||
|           <ActivityIndicator style={styles.activityIndicator} /> |  | ||||||
|         ) : ( |  | ||||||
|           <MaterialCommunityIcons |           <MaterialCommunityIcons | ||||||
|             name="access-point-network-off" |             name={icon} | ||||||
|             size={100} |             size={100} | ||||||
|             color={props.theme.colors.textDisabled} |             color={props.theme.colors.textDisabled} | ||||||
|             style={GENERAL_STYLES.center} |             style={GENERAL_STYLES.center} | ||||||
|           /> |           /> | ||||||
|         )} |         ) : null} | ||||||
|       </View> |       </View> | ||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
|  | @ -406,6 +404,7 @@ class HomeScreen extends React.Component<PropsType, StateType> { | ||||||
|   ): Array<{ |   ): Array<{ | ||||||
|     title: string; |     title: string; | ||||||
|     data: [] | Array<FeedItemType>; |     data: [] | Array<FeedItemType>; | ||||||
|  |     icon?: string; | ||||||
|     id: string; |     id: string; | ||||||
|   }> => { |   }> => { | ||||||
|     if (fetchedData) { |     if (fetchedData) { | ||||||
|  | @ -433,6 +432,7 @@ class HomeScreen extends React.Component<PropsType, StateType> { | ||||||
|           ? i18n.t('screens.home.feedLoading') |           ? i18n.t('screens.home.feedLoading') | ||||||
|           : i18n.t('screens.home.feedError'), |           : i18n.t('screens.home.feedError'), | ||||||
|         data: [], |         data: [], | ||||||
|  |         icon: isLoading ? undefined : 'access-point-network-off', | ||||||
|         id: SECTIONS_ID[1], |         id: SECTIONS_ID[1], | ||||||
|       }, |       }, | ||||||
|     ]; |     ]; | ||||||
|  | @ -473,7 +473,6 @@ class HomeScreen extends React.Component<PropsType, StateType> { | ||||||
|             renderItem={this.getRenderItem} |             renderItem={this.getRenderItem} | ||||||
|             itemHeight={FEED_ITEM_HEIGHT} |             itemHeight={FEED_ITEM_HEIGHT} | ||||||
|             onScroll={this.onScroll} |             onScroll={this.onScroll} | ||||||
|             showError={false} |  | ||||||
|             renderSectionHeader={this.getRenderSectionHeader} |             renderSectionHeader={this.getRenderSectionHeader} | ||||||
|             renderListHeaderComponent={this.getListHeader} |             renderListHeaderComponent={this.getListHeader} | ||||||
|           /> |           /> | ||||||
|  |  | ||||||
|  | @ -259,7 +259,7 @@ function GroupSelectionScreen() { | ||||||
|       createDataset={createDataset} |       createDataset={createDataset} | ||||||
|       refreshOnFocus={true} |       refreshOnFocus={true} | ||||||
|       renderItem={getRenderItem} |       renderItem={getRenderItem} | ||||||
|       updateData={currentSearchString + favoriteGroups.length} |       extraData={currentSearchString + favoriteGroups.length} | ||||||
|       cache={groups} |       cache={groups} | ||||||
|       onCacheUpdate={setGroups} |       onCacheUpdate={setGroups} | ||||||
|     /> |     /> | ||||||
|  |  | ||||||
|  | @ -512,7 +512,7 @@ class ProxiwashScreen extends React.Component<PropsType, StateType> { | ||||||
|             renderSectionHeader={this.getRenderSectionHeader} |             renderSectionHeader={this.getRenderSectionHeader} | ||||||
|             autoRefreshTime={REFRESH_TIME} |             autoRefreshTime={REFRESH_TIME} | ||||||
|             refreshOnFocus={true} |             refreshOnFocus={true} | ||||||
|             updateData={state.machinesWatched.length} |             extraData={state.machinesWatched.length} | ||||||
|           /> |           /> | ||||||
|         </View> |         </View> | ||||||
|         <MascotPopup |         <MascotPopup | ||||||
|  |  | ||||||
|  | @ -367,7 +367,7 @@ function ProximoListScreen(props: Props) { | ||||||
|         createDataset={createDataset} |         createDataset={createDataset} | ||||||
|         refreshOnFocus={true} |         refreshOnFocus={true} | ||||||
|         renderItem={getRenderItem} |         renderItem={getRenderItem} | ||||||
|         updateData={currentSearchString + currentSortMode} |         extraData={currentSearchString + currentSortMode} | ||||||
|         itemHeight={LIST_ITEM_HEIGHT} |         itemHeight={LIST_ITEM_HEIGHT} | ||||||
|         cache={articles} |         cache={articles} | ||||||
|         onCacheUpdate={setArticles} |         onCacheUpdate={setArticles} | ||||||
|  |  | ||||||
|  | @ -201,7 +201,7 @@ class SelfMenuScreen extends React.Component<PropsType> { | ||||||
|         refreshOnFocus={true} |         refreshOnFocus={true} | ||||||
|         renderItem={this.getRenderItem} |         renderItem={this.getRenderItem} | ||||||
|         renderSectionHeader={this.getRenderSectionHeader} |         renderSectionHeader={this.getRenderSectionHeader} | ||||||
|         stickyHeader={true} |         stickySectionHeadersEnabled={true} | ||||||
|       /> |       /> | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue