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