Browse Source

Use flatlist empty list render to display errors and loading

Arnaud Vergnet 4 years ago
parent
commit
784872ed96

+ 0
- 1
components/Custom/NetworkErrorComponent.js View File

7
 import i18n from 'i18n-js';
7
 import i18n from 'i18n-js';
8
 
8
 
9
 type Props = {
9
 type Props = {
10
-    navigation: Object,
11
     message: string,
10
     message: string,
12
     icon: string,
11
     icon: string,
13
     onRefresh: Function,
12
     onRefresh: Function,

+ 0
- 54
components/Lists/EmptyWebSectionListItem.js View File

1
-import * as React from 'react';
2
-import {ActivityIndicator, Subheading, withTheme} from 'react-native-paper';
3
-import {StyleSheet, View} from "react-native";
4
-import {MaterialCommunityIcons} from "@expo/vector-icons";
5
-
6
-/**
7
- * Component used to display a message when a list is empty
8
- *
9
- * @param props Props to pass to the component
10
- * @return {*}
11
- */
12
-function EmptyWebSectionListItem(props: { text: string, icon: string, refreshing: boolean, theme: {} }) {
13
-    const {colors} = props.theme;
14
-    return (
15
-        <View>
16
-            <View style={styles.iconContainer}>
17
-                {props.refreshing ?
18
-                    <ActivityIndicator
19
-                        animating={true}
20
-                        size={'large'}
21
-                        color={colors.primary}/>
22
-                    :
23
-                    <MaterialCommunityIcons
24
-                        name={props.icon}
25
-                        size={100}
26
-                        color={colors.textDisabled}/>}
27
-            </View>
28
-
29
-            <Subheading style={{
30
-                ...styles.subheading,
31
-                color: colors.textDisabled
32
-            }}>
33
-                {props.text}
34
-            </Subheading>
35
-        </View>
36
-    );
37
-}
38
-
39
-const styles = StyleSheet.create({
40
-    iconContainer: {
41
-        justifyContent: 'center',
42
-        alignItems: 'center',
43
-        width: '100%',
44
-        height: 100,
45
-        marginBottom: 20
46
-    },
47
-    subheading: {
48
-        textAlign: 'center',
49
-        marginRight: 20,
50
-        marginLeft: 20,
51
-    }
52
-});
53
-
54
-export default withTheme(EmptyWebSectionListItem);

+ 19
- 67
components/Lists/WebSectionList.js View File

5
 import i18n from "i18n-js";
5
 import i18n from "i18n-js";
6
 import {Snackbar} from 'react-native-paper';
6
 import {Snackbar} from 'react-native-paper';
7
 import {RefreshControl, SectionList, View} from "react-native";
7
 import {RefreshControl, SectionList, View} from "react-native";
8
-import EmptyWebSectionListItem from "./EmptyWebSectionListItem";
8
+import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
9
+import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
9
 
10
 
10
 type Props = {
11
 type Props = {
11
     navigation: Object,
12
     navigation: Object,
22
 type State = {
23
 type State = {
23
     refreshing: boolean,
24
     refreshing: boolean,
24
     firstLoading: boolean,
25
     firstLoading: boolean,
25
-    fetchedData: Object,
26
+    fetchedData: ?Object,
26
     snackbarVisible: boolean
27
     snackbarVisible: boolean
27
 };
28
 };
28
 
29
 
48
     state = {
49
     state = {
49
         refreshing: false,
50
         refreshing: false,
50
         firstLoading: true,
51
         firstLoading: true,
51
-        fetchedData: {},
52
+        fetchedData: undefined,
52
         snackbarVisible: false
53
         snackbarVisible: false
53
     };
54
     };
54
 
55
 
55
     onRefresh: Function;
56
     onRefresh: Function;
56
     onFetchSuccess: Function;
57
     onFetchSuccess: Function;
57
     onFetchError: Function;
58
     onFetchError: Function;
58
-    getEmptyRenderItem: Function;
59
     getEmptySectionHeader: Function;
59
     getEmptySectionHeader: Function;
60
     showSnackBar: Function;
60
     showSnackBar: Function;
61
     hideSnackBar: Function;
61
     hideSnackBar: Function;
66
         this.onRefresh = this.onRefresh.bind(this);
66
         this.onRefresh = this.onRefresh.bind(this);
67
         this.onFetchSuccess = this.onFetchSuccess.bind(this);
67
         this.onFetchSuccess = this.onFetchSuccess.bind(this);
68
         this.onFetchError = this.onFetchError.bind(this);
68
         this.onFetchError = this.onFetchError.bind(this);
69
-        this.getEmptyRenderItem = this.getEmptyRenderItem.bind(this);
70
         this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
69
         this.getEmptySectionHeader = this.getEmptySectionHeader.bind(this);
71
         this.showSnackBar = this.showSnackBar.bind(this);
70
         this.showSnackBar = this.showSnackBar.bind(this);
72
         this.hideSnackBar = this.hideSnackBar.bind(this);
71
         this.hideSnackBar = this.hideSnackBar.bind(this);
123
      */
122
      */
124
     onFetchError() {
123
     onFetchError() {
125
         this.setState({
124
         this.setState({
126
-            fetchedData: {},
125
+            fetchedData: undefined,
127
             refreshing: false,
126
             refreshing: false,
128
             firstLoading: false
127
             firstLoading: false
129
         });
128
         });
158
     }
157
     }
159
 
158
 
160
     /**
159
     /**
161
-     * Gets an empty render item
162
-     *
163
-     * @param item The data to display
164
-     * @return {*}
165
-     */
166
-    getEmptyRenderItem({item}: Object) {
167
-        return (
168
-            <EmptyWebSectionListItem
169
-                text={item.text}
170
-                icon={item.icon}
171
-                refreshing={this.state.refreshing}
172
-            />
173
-        );
174
-    }
175
-
176
-    /**
177
-     * Creates an empty dataset
178
-     *
179
-     * @return {*}
180
-     */
181
-    createEmptyDataset() {
182
-        return [
183
-            {
184
-                title: '',
185
-                data: [
186
-                    {
187
-                        text: this.state.refreshing ?
188
-                            i18n.t('general.loading') :
189
-                            i18n.t('general.networkError'),
190
-                        isSpinner: this.state.refreshing,
191
-                        icon: this.state.refreshing ?
192
-                            'refresh' :
193
-                            'access-point-network-off'
194
-                    }
195
-                ],
196
-                keyExtractor: this.datasetKeyExtractor,
197
-            }
198
-        ];
199
-    }
200
-
201
-    /**
202
-     * Extracts a key from the given item
203
-     *
204
-     * @param item The item to extract the key from
205
-     * @return {string} The extracted key
206
-     */
207
-    datasetKeyExtractor(item: Object): string {
208
-        return item.text
209
-    }
210
-
211
-    /**
212
      * Shows the error popup
160
      * Shows the error popup
213
      */
161
      */
214
     showSnackBar() {
162
     showSnackBar() {
223
     }
171
     }
224
 
172
 
225
     render() {
173
     render() {
226
-        let dataset = this.props.createDataset(this.state.fetchedData);
227
-        const isEmpty = dataset[0].data.length === 0;
228
-        const shouldRenderHeader = !isEmpty && (this.props.renderSectionHeader !== null);
229
-        if (isEmpty)
230
-            dataset = this.createEmptyDataset();
174
+        let dataset = [];
175
+        if (this.state.fetchedData !== undefined)
176
+            dataset = this.props.createDataset(this.state.fetchedData);
177
+        const shouldRenderHeader = this.props.renderSectionHeader !== null;
231
         return (
178
         return (
232
             <View>
179
             <View>
233
                 <Snackbar
180
                 <Snackbar
241
                 >
188
                 >
242
                     {i18n.t("homeScreen.listUpdateFail")}
189
                     {i18n.t("homeScreen.listUpdateFail")}
243
                 </Snackbar>
190
                 </Snackbar>
191
+                {/*$FlowFixMe*/}
244
                 <SectionList
192
                 <SectionList
245
                     sections={dataset}
193
                     sections={dataset}
246
                     refreshControl={
194
                     refreshControl={
252
                     //$FlowFixMe
200
                     //$FlowFixMe
253
                     renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
201
                     renderSectionHeader={shouldRenderHeader ? this.props.renderSectionHeader : this.getEmptySectionHeader}
254
                     //$FlowFixMe
202
                     //$FlowFixMe
255
-                    renderItem={isEmpty ? this.getEmptyRenderItem : this.props.renderItem}
256
-                    style={{minHeight: 300, width: '100%'}}
203
+                    renderItem={this.props.renderItem}
257
                     stickySectionHeadersEnabled={this.props.stickyHeader}
204
                     stickySectionHeadersEnabled={this.props.stickyHeader}
258
-                    contentContainerStyle={
259
-                        isEmpty ?
260
-                            {flexGrow: 1, justifyContent: 'center', alignItems: 'center'} : {}
205
+                    contentContainerStyle={{minHeight: '100%'}}
206
+                    style={{minHeight: '100%'}}
207
+                    ListEmptyComponent={this.state.refreshing
208
+                        ? <BasicLoadingScreen/>
209
+                        : <NetworkErrorComponent
210
+                            message={i18n.t('general.networkError')}
211
+                            icon={"access-point-network-off"}
212
+                            onRefresh={this.onRefresh}/>
261
                     }
213
                     }
262
                 />
214
                 />
263
             </View>
215
             </View>

Loading…
Cancel
Save