forked from vergnet/application-amicale
Use flatlist empty list render to display errors and loading
This commit is contained in:
parent
94d2db97ad
commit
784872ed96
3 changed files with 19 additions and 122 deletions
|
@ -7,7 +7,6 @@ import {MaterialCommunityIcons} from "@expo/vector-icons";
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object,
|
|
||||||
message: string,
|
message: string,
|
||||||
icon: string,
|
icon: string,
|
||||||
onRefresh: Function,
|
onRefresh: Function,
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import {ActivityIndicator, Subheading, withTheme} from 'react-native-paper';
|
|
||||||
import {StyleSheet, View} from "react-native";
|
|
||||||
import {MaterialCommunityIcons} from "@expo/vector-icons";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component used to display a message when a list is empty
|
|
||||||
*
|
|
||||||
* @param props Props to pass to the component
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
function EmptyWebSectionListItem(props: { text: string, icon: string, refreshing: boolean, theme: {} }) {
|
|
||||||
const {colors} = props.theme;
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<View style={styles.iconContainer}>
|
|
||||||
{props.refreshing ?
|
|
||||||
<ActivityIndicator
|
|
||||||
animating={true}
|
|
||||||
size={'large'}
|
|
||||||
color={colors.primary}/>
|
|
||||||
:
|
|
||||||
<MaterialCommunityIcons
|
|
||||||
name={props.icon}
|
|
||||||
size={100}
|
|
||||||
color={colors.textDisabled}/>}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Subheading style={{
|
|
||||||
...styles.subheading,
|
|
||||||
color: colors.textDisabled
|
|
||||||
}}>
|
|
||||||
{props.text}
|
|
||||||
</Subheading>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
iconContainer: {
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: '100%',
|
|
||||||
height: 100,
|
|
||||||
marginBottom: 20
|
|
||||||
},
|
|
||||||
subheading: {
|
|
||||||
textAlign: 'center',
|
|
||||||
marginRight: 20,
|
|
||||||
marginLeft: 20,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default withTheme(EmptyWebSectionListItem);
|
|
|
@ -5,7 +5,8 @@ import {readData} from "../../utils/WebData";
|
||||||
import i18n from "i18n-js";
|
import i18n from "i18n-js";
|
||||||
import {Snackbar} from 'react-native-paper';
|
import {Snackbar} from 'react-native-paper';
|
||||||
import {RefreshControl, SectionList, View} from "react-native";
|
import {RefreshControl, SectionList, View} from "react-native";
|
||||||
import EmptyWebSectionListItem from "./EmptyWebSectionListItem";
|
import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
|
||||||
|
import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
navigation: Object,
|
navigation: Object,
|
||||||
|
@ -22,7 +23,7 @@ type Props = {
|
||||||
type State = {
|
type State = {
|
||||||
refreshing: boolean,
|
refreshing: boolean,
|
||||||
firstLoading: boolean,
|
firstLoading: boolean,
|
||||||
fetchedData: Object,
|
fetchedData: ?Object,
|
||||||
snackbarVisible: boolean
|
snackbarVisible: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,14 +49,13 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
state = {
|
state = {
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
firstLoading: true,
|
firstLoading: true,
|
||||||
fetchedData: {},
|
fetchedData: undefined,
|
||||||
snackbarVisible: false
|
snackbarVisible: false
|
||||||
};
|
};
|
||||||
|
|
||||||
onRefresh: Function;
|
onRefresh: Function;
|
||||||
onFetchSuccess: Function;
|
onFetchSuccess: Function;
|
||||||
onFetchError: Function;
|
onFetchError: Function;
|
||||||
getEmptyRenderItem: Function;
|
|
||||||
getEmptySectionHeader: Function;
|
getEmptySectionHeader: Function;
|
||||||
showSnackBar: Function;
|
showSnackBar: Function;
|
||||||
hideSnackBar: Function;
|
hideSnackBar: Function;
|
||||||
|
@ -66,7 +66,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
this.onRefresh = this.onRefresh.bind(this);
|
this.onRefresh = this.onRefresh.bind(this);
|
||||||
this.onFetchSuccess = this.onFetchSuccess.bind(this);
|
this.onFetchSuccess = this.onFetchSuccess.bind(this);
|
||||||
this.onFetchError = this.onFetchError.bind(this);
|
this.onFetchError = this.onFetchError.bind(this);
|
||||||
this.getEmptyRenderItem = this.getEmptyRenderItem.bind(this);
|
|
||||||
this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
|
this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
|
||||||
this.showSnackBar = this.showSnackBar.bind(this);
|
this.showSnackBar = this.showSnackBar.bind(this);
|
||||||
this.hideSnackBar = this.hideSnackBar.bind(this);
|
this.hideSnackBar = this.hideSnackBar.bind(this);
|
||||||
|
@ -123,7 +122,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
*/
|
*/
|
||||||
onFetchError() {
|
onFetchError() {
|
||||||
this.setState({
|
this.setState({
|
||||||
fetchedData: {},
|
fetchedData: undefined,
|
||||||
refreshing: false,
|
refreshing: false,
|
||||||
firstLoading: false
|
firstLoading: false
|
||||||
});
|
});
|
||||||
|
@ -157,57 +156,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
return <View/>;
|
return <View/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an empty render item
|
|
||||||
*
|
|
||||||
* @param item The data to display
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
getEmptyRenderItem({item}: Object) {
|
|
||||||
return (
|
|
||||||
<EmptyWebSectionListItem
|
|
||||||
text={item.text}
|
|
||||||
icon={item.icon}
|
|
||||||
refreshing={this.state.refreshing}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an empty dataset
|
|
||||||
*
|
|
||||||
* @return {*}
|
|
||||||
*/
|
|
||||||
createEmptyDataset() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
title: '',
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
text: this.state.refreshing ?
|
|
||||||
i18n.t('general.loading') :
|
|
||||||
i18n.t('general.networkError'),
|
|
||||||
isSpinner: this.state.refreshing,
|
|
||||||
icon: this.state.refreshing ?
|
|
||||||
'refresh' :
|
|
||||||
'access-point-network-off'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
keyExtractor: this.datasetKeyExtractor,
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts a key from the given item
|
|
||||||
*
|
|
||||||
* @param item The item to extract the key from
|
|
||||||
* @return {string} The extracted key
|
|
||||||
*/
|
|
||||||
datasetKeyExtractor(item: Object): string {
|
|
||||||
return item.text
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the error popup
|
* Shows the error popup
|
||||||
*/
|
*/
|
||||||
|
@ -223,11 +171,10 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let dataset = this.props.createDataset(this.state.fetchedData);
|
let dataset = [];
|
||||||
const isEmpty = dataset[0].data.length === 0;
|
if (this.state.fetchedData !== undefined)
|
||||||
const shouldRenderHeader = !isEmpty && (this.props.renderSectionHeader !== null);
|
dataset = this.props.createDataset(this.state.fetchedData);
|
||||||
if (isEmpty)
|
const shouldRenderHeader = this.props.renderSectionHeader !== null;
|
||||||
dataset = this.createEmptyDataset();
|
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<Snackbar
|
<Snackbar
|
||||||
|
@ -241,6 +188,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
>
|
>
|
||||||
{i18n.t("homeScreen.listUpdateFail")}
|
{i18n.t("homeScreen.listUpdateFail")}
|
||||||
</Snackbar>
|
</Snackbar>
|
||||||
|
{/*$FlowFixMe*/}
|
||||||
<SectionList
|
<SectionList
|
||||||
sections={dataset}
|
sections={dataset}
|
||||||
refreshControl={
|
refreshControl={
|
||||||
|
@ -252,12 +200,16 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
|
||||||
//$FlowFixMe
|
//$FlowFixMe
|
||||||
renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
|
renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
|
||||||
//$FlowFixMe
|
//$FlowFixMe
|
||||||
renderItem={isEmpty ? this.getEmptyRenderItem : this.props.renderItem}
|
renderItem={this.props.renderItem}
|
||||||
style={{minHeight: 300, width: '100%'}}
|
|
||||||
stickySectionHeadersEnabled={this.props.stickyHeader}
|
stickySectionHeadersEnabled={this.props.stickyHeader}
|
||||||
contentContainerStyle={
|
contentContainerStyle={{minHeight: '100%'}}
|
||||||
isEmpty ?
|
style={{minHeight: '100%'}}
|
||||||
{flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
|
ListEmptyComponent={this.state.refreshing
|
||||||
|
? <BasicLoadingScreen/>
|
||||||
|
: <NetworkErrorComponent
|
||||||
|
message={i18n.t('general.networkError')}
|
||||||
|
icon={"access-point-network-off"}
|
||||||
|
onRefresh={this.onRefresh}/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
Loading…
Reference in a new issue