Browse Source

Improve request error handling

Arnaud Vergnet 2 years ago
parent
commit
d55c692bd3

+ 36
- 7
src/components/Screens/RequestScreen.tsx View File

1
 import React, { useEffect, useRef } from 'react';
1
 import React, { useEffect, useRef } from 'react';
2
 import ErrorView from './ErrorView';
2
 import ErrorView from './ErrorView';
3
 import { useRequestLogic } from '../../utils/customHooks';
3
 import { useRequestLogic } from '../../utils/customHooks';
4
-import { useFocusEffect } from '@react-navigation/native';
4
+import {
5
+  useFocusEffect,
6
+  useNavigation,
7
+  useRoute,
8
+} from '@react-navigation/native';
5
 import BasicLoadingScreen from './BasicLoadingScreen';
9
 import BasicLoadingScreen from './BasicLoadingScreen';
6
 import i18n from 'i18n-js';
10
 import i18n from 'i18n-js';
7
 import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
11
 import { API_REQUEST_CODES, REQUEST_STATUS } from '../../utils/Requests';
12
+import { StackNavigationProp } from '@react-navigation/stack';
13
+import { MainRoutes } from '../../navigation/MainNavigator';
14
+import ConnectionManager from '../../managers/ConnectionManager';
8
 
15
 
9
 export type RequestScreenProps<T> = {
16
 export type RequestScreenProps<T> = {
10
   request: () => Promise<T>;
17
   request: () => Promise<T>;
37
 const MIN_REFRESH_TIME = 5 * 1000;
44
 const MIN_REFRESH_TIME = 5 * 1000;
38
 
45
 
39
 export default function RequestScreen<T>(props: Props<T>) {
46
 export default function RequestScreen<T>(props: Props<T>) {
47
+  const navigation = useNavigation<StackNavigationProp<any>>();
48
+  const route = useRoute();
40
   const refreshInterval = useRef<number>();
49
   const refreshInterval = useRef<number>();
41
   const [
50
   const [
42
     loading,
51
     loading,
89
     }, [props.cache, props.refreshOnFocus])
98
     }, [props.cache, props.refreshOnFocus])
90
   );
99
   );
91
 
100
 
101
+  const isErrorCritical = (e: API_REQUEST_CODES | undefined) => {
102
+    return e === API_REQUEST_CODES.BAD_TOKEN;
103
+  };
104
+
105
+  useEffect(() => {
106
+    if (isErrorCritical(code)) {
107
+      ConnectionManager.getInstance()
108
+        .disconnect()
109
+        .then(() => {
110
+          navigation.replace(MainRoutes.Login, { nextScreen: route.name });
111
+        });
112
+    }
113
+  }, [code, navigation, route]);
114
+
92
   if (data === undefined && loading && props.showLoading !== false) {
115
   if (data === undefined && loading && props.showLoading !== false) {
93
     return <BasicLoadingScreen />;
116
     return <BasicLoadingScreen />;
94
   } else if (
117
   } else if (
95
     data === undefined &&
118
     data === undefined &&
96
-    status !== REQUEST_STATUS.SUCCESS &&
119
+    (status !== REQUEST_STATUS.SUCCESS ||
120
+      (status === REQUEST_STATUS.SUCCESS && code !== undefined)) &&
97
     props.showError !== false
121
     props.showError !== false
98
   ) {
122
   ) {
99
     return (
123
     return (
100
       <ErrorView
124
       <ErrorView
101
         status={status}
125
         status={status}
126
+        code={code}
102
         loading={loading}
127
         loading={loading}
103
-        button={{
104
-          icon: 'refresh',
105
-          text: i18n.t('general.retry'),
106
-          onPress: () => refreshData(),
107
-        }}
128
+        button={
129
+          isErrorCritical(code)
130
+            ? undefined
131
+            : {
132
+                icon: 'refresh',
133
+                text: i18n.t('general.retry'),
134
+                onPress: () => refreshData(),
135
+              }
136
+        }
108
       />
137
       />
109
     );
138
     );
110
   } else {
139
   } else {

+ 1
- 1
src/screens/Amicale/Clubs/ClubListScreen.tsx View File

156
       this.categories = data?.categories;
156
       this.categories = data?.categories;
157
       return [{ title: '', data: data.clubs }];
157
       return [{ title: '', data: data.clubs }];
158
     } else {
158
     } else {
159
-      return [{ title: '', data: [] }];
159
+      return [];
160
     }
160
     }
161
   };
161
   };
162
 
162
 

+ 1
- 1
src/screens/Amicale/Equipment/EquipmentListScreen.tsx View File

136
       }
136
       }
137
       return [{ title: '', data: data.devices }];
137
       return [{ title: '', data: data.devices }];
138
     } else {
138
     } else {
139
-      return [{ title: '', data: [] }];
139
+      return [];
140
     }
140
     }
141
   };
141
   };
142
 
142
 

+ 3
- 4
src/screens/Amicale/LoginScreen.tsx View File

110
       this.onInputChange(false, value);
110
       this.onInputChange(false, value);
111
     };
111
     };
112
     props.navigation.addListener('focus', this.onScreenFocus);
112
     props.navigation.addListener('focus', this.onScreenFocus);
113
-    // TODO remove
114
     this.state = {
113
     this.state = {
115
-      email: 'vergnet@etud.insa-toulouse.fr',
116
-      password: 'IGtt25ùj',
114
+      email: '',
115
+      password: '',
117
       isEmailValidated: false,
116
       isEmailValidated: false,
118
       isPasswordValidated: false,
117
       isPasswordValidated: false,
119
       loading: false,
118
       loading: false,
373
    * Saves the screen to navigate to after a successful login if one was provided in navigation parameters
372
    * Saves the screen to navigate to after a successful login if one was provided in navigation parameters
374
    */
373
    */
375
   handleNavigationParams() {
374
   handleNavigationParams() {
376
-    this.nextScreen = this.props.route.params.nextScreen;
375
+    this.nextScreen = this.props.route.params?.nextScreen;
377
   }
376
   }
378
 
377
 
379
   /**
378
   /**

+ 34
- 35
src/screens/Planex/GroupSelectionScreen.tsx View File

121
         }
121
         }
122
       | undefined
122
       | undefined
123
   ): Array<{ title: string; data: Array<PlanexGroupCategoryType> }> => {
123
   ): Array<{ title: string; data: Array<PlanexGroupCategoryType> }> => {
124
-    return [
125
-      {
126
-        title: '',
127
-        data: generateData(fetchedData),
128
-      },
129
-    ];
124
+    if (fetchedData) {
125
+      return [
126
+        {
127
+          title: '',
128
+          data: generateData(fetchedData),
129
+        },
130
+      ];
131
+    } else {
132
+      return [];
133
+    }
130
   };
134
   };
131
 
135
 
132
   /**
136
   /**
181
    * @returns {[]}
185
    * @returns {[]}
182
    */
186
    */
183
   const generateData = (
187
   const generateData = (
184
-    fetchedData: PlanexGroupsType | undefined
188
+    fetchedData: PlanexGroupsType
185
   ): Array<PlanexGroupCategoryType> => {
189
   ): Array<PlanexGroupCategoryType> => {
186
     const data: Array<PlanexGroupCategoryType> = [];
190
     const data: Array<PlanexGroupCategoryType> = [];
187
-
188
-    if (fetchedData) {
189
-      // Convert the object into an array
190
-      Object.values(fetchedData).forEach(
191
-        (category: PlanexGroupCategoryType) => {
192
-          const content: Array<PlanexGroupType> = [];
193
-          // Filter groups matching the search query
194
-          category.content.forEach((g: PlanexGroupType) => {
195
-            if (stringMatchQuery(g.name, currentSearchString)) {
196
-              content.push(g);
197
-            }
198
-          });
199
-          // Only add categories with groups matching the query
200
-          if (content.length > 0) {
201
-            data.push({
202
-              id: category.id,
203
-              name: category.name,
204
-              content: content,
205
-            });
206
-          }
191
+    // Convert the object into an array
192
+    Object.values(fetchedData).forEach((category: PlanexGroupCategoryType) => {
193
+      const content: Array<PlanexGroupType> = [];
194
+      // Filter groups matching the search query
195
+      category.content.forEach((g: PlanexGroupType) => {
196
+        if (stringMatchQuery(g.name, currentSearchString)) {
197
+          content.push(g);
207
         }
198
         }
208
-      );
209
-      data.sort(sortName);
210
-      // Add the favorites at the top
211
-      data.unshift({
212
-        name: i18n.t('screens.planex.favorites.title'),
213
-        id: 0,
214
-        content: favoriteGroups,
215
       });
199
       });
216
-    }
200
+      // Only add categories with groups matching the query
201
+      if (content.length > 0) {
202
+        data.push({
203
+          id: category.id,
204
+          name: category.name,
205
+          content: content,
206
+        });
207
+      }
208
+    });
209
+    data.sort(sortName);
210
+    // Add the favorites at the top
211
+    data.unshift({
212
+      name: i18n.t('screens.planex.favorites.title'),
213
+      id: 0,
214
+      content: favoriteGroups,
215
+    });
217
     return data;
216
     return data;
218
   };
217
   };
219
 
218
 

+ 1
- 7
src/screens/Services/Proximo/ProximoListScreen.tsx View File

349
         },
349
         },
350
       ];
350
       ];
351
     } else {
351
     } else {
352
-      return [
353
-        {
354
-          title: '',
355
-          data: [],
356
-          keyExtractor: keyExtractor,
357
-        },
358
-      ];
352
+      return [];
359
     }
353
     }
360
   };
354
   };
361
 
355
 

+ 1
- 7
src/screens/Services/Proximo/ProximoMainScreen.tsx View File

239
         },
239
         },
240
       ];
240
       ];
241
     } else {
241
     } else {
242
-      return [
243
-        {
244
-          title: '',
245
-          data: [],
246
-          keyExtractor: getKeyExtractor,
247
-        },
248
-      ];
242
+      return [];
249
     }
243
     }
250
   };
244
   };
251
 
245
 

+ 23
- 16
src/screens/Services/SelfMenuScreen.tsx View File

27
 import type { SectionListDataType } from '../../components/Screens/WebSectionList';
27
 import type { SectionListDataType } from '../../components/Screens/WebSectionList';
28
 import Urls from '../../constants/Urls';
28
 import Urls from '../../constants/Urls';
29
 import { readData } from '../../utils/WebData';
29
 import { readData } from '../../utils/WebData';
30
+import { REQUEST_STATUS } from '../../utils/Requests';
30
 
31
 
31
 type PropsType = {
32
 type PropsType = {
32
   navigation: StackNavigationProp<any>;
33
   navigation: StackNavigationProp<any>;
109
    * @return {[]}
110
    * @return {[]}
110
    */
111
    */
111
   createDataset = (
112
   createDataset = (
112
-    fetchedData: Array<RawRuMenuType> | undefined
113
+    fetchedData: Array<RawRuMenuType> | undefined,
114
+    _loading: boolean,
115
+    _lastRefreshDate: Date | undefined,
116
+    _refreshData: (newRequest?: () => Promise<Array<RawRuMenuType>>) => void,
117
+    status: REQUEST_STATUS
113
   ): SectionListDataType<RuFoodCategoryType> => {
118
   ): SectionListDataType<RuFoodCategoryType> => {
114
     let result: SectionListDataType<RuFoodCategoryType> = [];
119
     let result: SectionListDataType<RuFoodCategoryType> = [];
115
-    if (fetchedData == null || fetchedData.length === 0) {
116
-      result = [
117
-        {
118
-          title: i18n.t('general.notAvailable'),
119
-          data: [],
120
-          keyExtractor: this.getKeyExtractor,
121
-        },
122
-      ];
123
-    } else {
124
-      fetchedData.forEach((item: RawRuMenuType) => {
125
-        result.push({
126
-          title: DateManager.getInstance().getTranslatedDate(item.date),
127
-          data: item.meal[0].foodcategory,
128
-          keyExtractor: this.getKeyExtractor,
120
+    if (status === REQUEST_STATUS.SUCCESS) {
121
+      if (fetchedData == null || fetchedData.length === 0) {
122
+        result = [
123
+          {
124
+            title: i18n.t('general.notAvailable'),
125
+            data: [],
126
+            keyExtractor: this.getKeyExtractor,
127
+          },
128
+        ];
129
+      } else {
130
+        fetchedData.forEach((item: RawRuMenuType) => {
131
+          result.push({
132
+            title: DateManager.getInstance().getTranslatedDate(item.date),
133
+            data: item.meal[0].foodcategory,
134
+            keyExtractor: this.getKeyExtractor,
135
+          });
129
         });
136
         });
130
-      });
137
+      }
131
     }
138
     }
132
     return result;
139
     return result;
133
   };
140
   };

Loading…
Cancel
Save