Browse Source

Improved error handling

Arnaud Vergnet 4 years ago
parent
commit
c70bafe273

+ 3
- 27
src/components/Amicale/AuthenticatedScreen.js View File

@@ -3,8 +3,7 @@
3 3
 import * as React from 'react';
4 4
 import {withTheme} from 'react-native-paper';
5 5
 import ConnectionManager, {ERROR_TYPE} from "../../managers/ConnectionManager";
6
-import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
7
-import i18n from 'i18n-js';
6
+import ErrorView from "../Custom/ErrorView";
8 7
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
9 8
 
10 9
 type Props = {
@@ -98,32 +97,9 @@ class AuthenticatedScreen extends React.Component<Props, State> {
98 97
     }
99 98
 
100 99
     getErrorRender() {
101
-        let message;
102
-        let icon;
103
-        switch (this.errorCode) {
104
-            case ERROR_TYPE.BAD_CREDENTIALS:
105
-                message = i18n.t("loginScreen.errors.credentials");
106
-                icon = "account-alert-outline";
107
-                break;
108
-            case ERROR_TYPE.BAD_TOKEN:
109
-                message = "BAD TOKEN"; // TODO translate
110
-                icon = "access-point-network-off";
111
-                break;
112
-            case ERROR_TYPE.CONNECTION_ERROR:
113
-                message = i18n.t("loginScreen.errors.connection");
114
-                icon = "access-point-network-off";
115
-                break;
116
-            default:
117
-                message = i18n.t("loginScreen.errors.unknown");
118
-                icon = "alert-circle-outline";
119
-                break;
120
-        }
121
-
122 100
         return (
123
-            <NetworkErrorComponent
124
-                {...this.props}
125
-                icon={icon}
126
-                message={message}
101
+            <ErrorView
102
+                errorCode={this.errorCode}
127 103
                 onRefresh={this.fetchData}
128 104
             />
129 105
         );

src/components/Custom/NetworkErrorComponent.js → src/components/Custom/ErrorView.js View File

@@ -5,10 +5,10 @@ import {Button, Subheading, withTheme} from 'react-native-paper';
5 5
 import {StyleSheet, View} from "react-native";
6 6
 import {MaterialCommunityIcons} from "@expo/vector-icons";
7 7
 import i18n from 'i18n-js';
8
+import {ERROR_TYPE} from "../../managers/ConnectionManager";
8 9
 
9 10
 type Props = {
10
-    message: string,
11
-    icon: string,
11
+    errorCode: number,
12 12
     onRefresh: Function,
13 13
 }
14 14
 
@@ -16,10 +16,13 @@ type State = {
16 16
     refreshing: boolean,
17 17
 }
18 18
 
19
-class NetworkErrorComponent extends React.PureComponent<Props, State> {
19
+class ErrorView extends React.PureComponent<Props, State> {
20 20
 
21 21
     colors: Object;
22 22
 
23
+    message: string;
24
+    icon: string;
25
+
23 26
     state = {
24 27
         refreshing: false,
25 28
     };
@@ -29,7 +32,45 @@ class NetworkErrorComponent extends React.PureComponent<Props, State> {
29 32
         this.colors = props.theme.colors;
30 33
     }
31 34
 
35
+    generateMessage() {
36
+        switch (this.props.errorCode) {
37
+            case ERROR_TYPE.BAD_CREDENTIALS:
38
+                this.message = i18n.t("errors.badCredentials");
39
+                this.icon = "account-alert-outline";
40
+                break;
41
+            case ERROR_TYPE.BAD_TOKEN:
42
+                this.message = i18n.t("errors.badToken");
43
+                this.icon = "account-alert-outline";
44
+                break;
45
+            case ERROR_TYPE.NO_CONSENT:
46
+                this.message = i18n.t("errors.noConsent");
47
+                this.icon = "account-remove-outline";
48
+                break;
49
+            case ERROR_TYPE.BAD_INPUT:
50
+                this.message = i18n.t("errors.badInput");
51
+                this.icon = "alert-circle-outline";
52
+                break;
53
+            case ERROR_TYPE.FORBIDDEN:
54
+                this.message = i18n.t("errors.forbidden");
55
+                this.icon = "lock";
56
+                break;
57
+            case ERROR_TYPE.CONNECTION_ERROR:
58
+                this.message = i18n.t("errors.connectionError");
59
+                this.icon = "access-point-network-off";
60
+                break;
61
+            case ERROR_TYPE.SERVER_ERROR:
62
+                this.message = i18n.t("errors.serverError");
63
+                this.icon = "server-network-off";
64
+                break;
65
+            default:
66
+                this.message = i18n.t("errors.unknown");
67
+                this.icon = "alert-circle-outline";
68
+                break;
69
+        }
70
+    }
71
+
32 72
     render() {
73
+        this.generateMessage();
33 74
         return (
34 75
             <View style={{
35 76
                 ...styles.outer,
@@ -38,7 +79,7 @@ class NetworkErrorComponent extends React.PureComponent<Props, State> {
38 79
                 <View style={styles.inner}>
39 80
                     <View style={styles.iconContainer}>
40 81
                         <MaterialCommunityIcons
41
-                            name={this.props.icon}
82
+                            name={this.icon}
42 83
                             size={150}
43 84
                             color={this.colors.textDisabled}/>
44 85
                     </View>
@@ -46,7 +87,7 @@ class NetworkErrorComponent extends React.PureComponent<Props, State> {
46 87
                         ...styles.subheading,
47 88
                         color: this.colors.textDisabled
48 89
                     }}>
49
-                        {this.props.message}
90
+                        {this.message}
50 91
                     </Subheading>
51 92
                     <Button
52 93
                         mode={'contained'}
@@ -86,4 +127,4 @@ const styles = StyleSheet.create({
86 127
 });
87 128
 
88 129
 
89
-export default withTheme(NetworkErrorComponent);
130
+export default withTheme(ErrorView);

+ 15
- 6
src/components/Dialog/ErrorDialog.js View File

@@ -15,22 +15,31 @@ class ErrorDialog extends React.PureComponent<Props> {
15 15
     message: string;
16 16
 
17 17
     generateMessage() {
18
-        this.title = i18n.t("loginScreen.errors.title");
18
+        this.title = i18n.t("errors.title");
19 19
         switch (this.props.errorCode) {
20 20
             case ERROR_TYPE.BAD_CREDENTIALS:
21
-                this.message = i18n.t("loginScreen.errors.credentials");
21
+                this.message = i18n.t("errors.badCredentials");
22
+                break;
23
+            case ERROR_TYPE.BAD_TOKEN:
24
+                this.message = i18n.t("errors.badToken");
22 25
                 break;
23 26
             case ERROR_TYPE.NO_CONSENT:
24
-                this.message = i18n.t("loginScreen.errors.consent");
27
+                this.message = i18n.t("errors.noConsent");
28
+                break;
29
+            case ERROR_TYPE.BAD_INPUT:
30
+                this.message = i18n.t("errors.badInput");
31
+                break;
32
+            case ERROR_TYPE.FORBIDDEN:
33
+                this.message = i18n.t("errors.forbidden");
25 34
                 break;
26 35
             case ERROR_TYPE.CONNECTION_ERROR:
27
-                this.message = i18n.t("loginScreen.errors.connection");
36
+                this.message = i18n.t("errors.connectionError");
28 37
                 break;
29 38
             case ERROR_TYPE.SERVER_ERROR:
30
-                this.message = "SERVER ERROR"; // TODO translate
39
+                this.message = i18n.t("errors.serverError");
31 40
                 break;
32 41
             default:
33
-                this.message = i18n.t("loginScreen.errors.unknown");
42
+                this.message = i18n.t("errors.unknown");
34 43
                 break;
35 44
         }
36 45
     }

+ 4
- 4
src/components/Lists/WebSectionList.js View File

@@ -5,8 +5,9 @@ import {readData} from "../../utils/WebData";
5 5
 import i18n from "i18n-js";
6 6
 import {Snackbar} from 'react-native-paper';
7 7
 import {RefreshControl, SectionList, View} from "react-native";
8
-import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
8
+import ErrorView from "../Custom/ErrorView";
9 9
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
10
+import {ERROR_TYPE} from "../../managers/ConnectionManager";
10 11
 
11 12
 type Props = {
12 13
     navigation: Object,
@@ -192,9 +193,8 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
192 193
                     style={{minHeight: '100%'}}
193 194
                     ListEmptyComponent={this.state.refreshing
194 195
                         ? <BasicLoadingScreen/>
195
-                        : <NetworkErrorComponent
196
-                            message={i18n.t('general.networkError')}
197
-                            icon={"access-point-network-off"}
196
+                        : <ErrorView
197
+                            errorCode={ERROR_TYPE.CONNECTION_ERROR}
198 198
                             onRefresh={this.onRefresh}/>
199 199
                     }
200 200
                     getItemLayout={this.props.itemHeight !== undefined ? this.itemLayout : undefined}

+ 12
- 37
src/components/Screens/WebViewScreen.js View File

@@ -2,11 +2,10 @@
2 2
 
3 3
 import * as React from 'react';
4 4
 import WebView from "react-native-webview";
5
-import {withTheme} from 'react-native-paper';
6 5
 import HeaderButton from "../Custom/HeaderButton";
7 6
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
8
-import NetworkErrorComponent from "../Custom/NetworkErrorComponent";
9
-import i18n from "i18n-js";
7
+import ErrorView from "../Custom/ErrorView";
8
+import {ERROR_TYPE} from "../../managers/ConnectionManager";
10 9
 
11 10
 type Props = {
12 11
     navigation: Object,
@@ -32,20 +31,12 @@ class WebViewScreen extends React.PureComponent<Props> {
32 31
         hasSideMenu: true,
33 32
         hasFooter: true,
34 33
     };
35
-    webviewRef: Object;
36
-
37
-    onRefreshClicked: Function;
38
-    onWebviewRef: Function;
39
-    getRenderLoading: Function;
40 34
 
41
-    colors: Object;
35
+    webviewRef: Object;
42 36
 
43
-    constructor(props) {
44
-        super(props);
45
-        this.onRefreshClicked = this.onRefreshClicked.bind(this);
46
-        this.onWebviewRef = this.onWebviewRef.bind(this);
47
-        this.getRenderLoading = this.getRenderLoading.bind(this);
48
-        this.colors = props.theme.colors;
37
+    constructor() {
38
+        super();
39
+        this.webviewRef = React.createRef();
49 40
     }
50 41
 
51 42
     /**
@@ -70,33 +61,19 @@ class WebViewScreen extends React.PureComponent<Props> {
70 61
     /**
71 62
      * Callback to use when refresh button is clicked. Reloads the webview.
72 63
      */
73
-    onRefreshClicked() {
74
-        if (this.webviewRef !== null)
75
-            this.webviewRef.reload();
76
-    }
77
-
78
-    /**
79
-     * Callback used when receiving the webview ref. Stores the ref for later use
80
-     *
81
-     * @param ref
82
-     */
83
-    onWebviewRef(ref: Object) {
84
-        this.webviewRef = ref
85
-    }
64
+    onRefreshClicked = () => this.webviewRef.current.reload();
86 65
 
87 66
     /**
88 67
      * Gets the loading indicator
89 68
      *
90 69
      * @return {*}
91 70
      */
92
-    getRenderLoading() {
93
-        return <BasicLoadingScreen/>;
94
-    }
71
+    getRenderLoading = () => <BasicLoadingScreen/>;
95 72
 
96 73
     render() {
97 74
         return (
98 75
             <WebView
99
-                ref={this.onWebviewRef}
76
+                ref={this.webviewRef}
100 77
                 source={{uri: this.props.data[0]['url']}}
101 78
                 style={{
102 79
                     width: '100%',
@@ -106,15 +83,13 @@ class WebViewScreen extends React.PureComponent<Props> {
106 83
                 injectedJavaScript={this.props.data[0]['customJS']}
107 84
                 javaScriptEnabled={true}
108 85
                 renderLoading={this.getRenderLoading}
109
-                renderError={() => <NetworkErrorComponent
110
-                    {...this.props}
86
+                renderError={() => <ErrorView
87
+                    errorCode={ERROR_TYPE.CONNECTION_ERROR}
111 88
                     onRefresh={this.onRefreshClicked}
112
-                    message={i18n.t("loginScreen.errors.connection")}
113
-                    icon={'access-point-network-off'}
114 89
                 />}
115 90
             />
116 91
         );
117 92
     }
118 93
 }
119 94
 
120
-export default withTheme(WebViewScreen);
95
+export default WebViewScreen;

+ 11
- 8
translations/en.json View File

@@ -237,14 +237,17 @@
237 237
     "whyAccountParagraph": "An Amicale account allows you to take part in several activities around campus. You can join a club, or even create your own!",
238 238
     "whyAccountParagraph2": "Logging into your Amicale account on the app will allow you to see all available clubs on the campus, vote for the upcoming elections, and more to come!",
239 239
     "noAccount": "No Account? Go to the Amicale's building during open hours to create one.",
240
-    "errors": {
241
-      "title": "Error!",
242
-      "connection": "Network error. Please check your internet connection.",
243
-      "credentials": "Email or password invalid.",
244
-      "saveToken": "Failed to save connection information, please contact support.",
245
-      "consent": "You did not give your consent for data processing to the Amicale.",
246
-      "unknown": "Unknown error, please contact support."
247
-    }
240
+  },
241
+  "errors": {
242
+    "title": "Error!",
243
+    "badCredentials": "Email or password invalid.",
244
+    "badToken": "Session expired, please login again.",
245
+    "noConsent": "You did not give your consent for data processing to the Amicale.",
246
+    "badInput": "Invalid input. Please try again.",
247
+    "forbidden": "You do not have access to this data.",
248
+    "connectionError": "Network error. Please check your internet connection.",
249
+    "serverError": "Server error. Please contact support.",
250
+    "unknown": "Unknown error. Please contact support."
248 251
   },
249 252
   "clubs": {
250 253
     "clubList": "Club list",

+ 12
- 9
translations/fr.json View File

@@ -236,15 +236,18 @@
236 236
     "whyAccountSub": "Ce que vous pouvez faire avec un compte",
237 237
     "whyAccountParagraph": "Un compte Amicale vous donne la possibilité de participer à diverses activités sur le campus. Vous pouvez rejoindre des clubs ou même créer le votre !",
238 238
     "whyAccountParagraph2": "Vous connecter à votre compte Amicale sur l'appli vous permettra de voir tous les clubs en activité, de voter pour les prochaines élections, et plus à venir !",
239
-    "noAccount": "Pas de compte ? Passez à l'Amicale pendant une perm pour en créer un.",
240
-    "errors": {
241
-      "title": "Erreur !",
242
-      "connection": "Erreur de réseau. Merci de vérifier votre connexion Internet.",
243
-      "credentials": "Email ou mot de passe invalide.",
244
-      "saveToken": "Erreur de sauvegarde des informations de connexion, merci de contacter le support.",
245
-      "consent": "Vous n'avez pas donné votre consentement pour l'utilisation de vos données personnelles.",
246
-      "unknown": "Erreur inconnue, merci de contacter le support."
247
-    }
239
+    "noAccount": "Pas de compte ? Passez à l'Amicale pendant une perm pour en créer un."
240
+  },
241
+  "errors": {
242
+    "title": "Erreur !",
243
+    "badCredentials": "Email ou mot de passe invalide.",
244
+    "badToken": "Session expirée, merci de vous reconnecter.",
245
+    "noConsent": "Vous n'avez pas donné votre consentement pour l'utilisation de vos données personnelles.",
246
+    "badInput": "Entrée invalide. Merci de réessayer.",
247
+    "forbidden": "Vous n'avez pas accès à cette information.",
248
+    "connectionError": "Erreur de réseau. Merci de vérifier votre connexion Internet.",
249
+    "serverError": "Erreur de serveur. Merci de contacter le support.",
250
+    "unknown": "Erreur inconnue. Merci de contacter le support."
248 251
   },
249 252
   "clubs": {
250 253
     "clubList": "Liste des clubs",

Loading…
Cancel
Save