Browse Source

Improved error handling and added new api endpoints

Arnaud Vergnet 4 years ago
parent
commit
0ba48adb6e

+ 2
- 42
__tests__/managers/ConnectionManager.test.js View File

1
 import React from 'react';
1
 import React from 'react';
2
-import ConnectionManager, {ERROR_TYPE} from "../../src/managers/ConnectionManager";
2
+import ConnectionManager from "../../src/managers/ConnectionManager";
3
+import {ERROR_TYPE} from "../../src/utils/WebData";
3
 import * as SecureStore from 'expo-secure-store';
4
 import * as SecureStore from 'expo-secure-store';
4
 
5
 
5
 let fetch = require('isomorphic-fetch'); // fetch is not implemented in nodeJS but in react-native
6
 let fetch = require('isomorphic-fetch'); // fetch is not implemented in nodeJS but in react-native
63
     return expect(c.recoverLogin()).resolves.toBe('token2');
64
     return expect(c.recoverLogin()).resolves.toBe('token2');
64
 });
65
 });
65
 
66
 
66
-test('isRequestResponseValid', () => {
67
-    let json = {
68
-        error: 0,
69
-        data: {}
70
-    };
71
-    expect(c.isResponseValid(json)).toBeTrue();
72
-    json = {
73
-        error: 1,
74
-        data: {}
75
-    };
76
-    expect(c.isResponseValid(json)).toBeTrue();
77
-    json = {
78
-        error: 50,
79
-        data: {}
80
-    };
81
-    expect(c.isResponseValid(json)).toBeTrue();
82
-    json = {
83
-        error: 50,
84
-        data: {truc: 'machin'}
85
-    };
86
-    expect(c.isResponseValid(json)).toBeTrue();
87
-    json = {
88
-        message: 'coucou'
89
-    };
90
-    expect(c.isResponseValid(json)).toBeFalse();
91
-    json = {
92
-        error: 'coucou',
93
-        data: {truc: 'machin'}
94
-    };
95
-    expect(c.isResponseValid(json)).toBeFalse();
96
-    json = {
97
-        error: 0,
98
-        data: 'coucou'
99
-    };
100
-    expect(c.isResponseValid(json)).toBeFalse();
101
-    json = {
102
-        error: 0,
103
-    };
104
-    expect(c.isResponseValid(json)).toBeFalse();
105
-});
106
-
107
 test("isConnectionResponseValid", () => {
67
 test("isConnectionResponseValid", () => {
108
     let json = {
68
     let json = {
109
         error: 0,
69
         error: 0,

+ 45
- 0
__tests__/utils/WebData.js View File

1
+import React from 'react';
2
+import {isResponseValid} from "../../src/utils/WebData";
3
+
4
+let fetch = require('isomorphic-fetch'); // fetch is not implemented in nodeJS but in react-native
5
+
6
+test('isRequestResponseValid', () => {
7
+    let json = {
8
+        error: 0,
9
+        data: {}
10
+    };
11
+    expect(isResponseValid(json)).toBeTrue();
12
+    json = {
13
+        error: 1,
14
+        data: {}
15
+    };
16
+    expect(isResponseValid(json)).toBeTrue();
17
+    json = {
18
+        error: 50,
19
+        data: {}
20
+    };
21
+    expect(isResponseValid(json)).toBeTrue();
22
+    json = {
23
+        error: 50,
24
+        data: {truc: 'machin'}
25
+    };
26
+    expect(isResponseValid(json)).toBeTrue();
27
+    json = {
28
+        message: 'coucou'
29
+    };
30
+    expect(isResponseValid(json)).toBeFalse();
31
+    json = {
32
+        error: 'coucou',
33
+        data: {truc: 'machin'}
34
+    };
35
+    expect(isResponseValid(json)).toBeFalse();
36
+    json = {
37
+        error: 0,
38
+        data: 'coucou'
39
+    };
40
+    expect(isResponseValid(json)).toBeFalse();
41
+    json = {
42
+        error: 0,
43
+    };
44
+    expect(isResponseValid(json)).toBeFalse();
45
+});

+ 18
- 11
src/components/Amicale/AuthenticatedScreen.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import * as React from 'react';
3
 import * as React from 'react';
4
-import ConnectionManager, {ERROR_TYPE} from "../../managers/ConnectionManager";
4
+import ConnectionManager from "../../managers/ConnectionManager";
5
+import {ERROR_TYPE} from "../../utils/WebData";
5
 import ErrorView from "../Custom/ErrorView";
6
 import ErrorView from "../Custom/ErrorView";
6
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
7
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
7
 
8
 
8
 type Props = {
9
 type Props = {
9
     navigation: Object,
10
     navigation: Object,
10
-    links: Array<{link: string, mandatory: boolean}>,
11
+    requests: Array<{
12
+        link: string,
13
+        params: Object,
14
+        mandatory: boolean
15
+    }>,
11
     renderFunction: Function,
16
     renderFunction: Function,
12
 }
17
 }
13
 
18
 
30
         super(props);
35
         super(props);
31
         this.connectionManager = ConnectionManager.getInstance();
36
         this.connectionManager = ConnectionManager.getInstance();
32
         this.props.navigation.addListener('focus', this.onScreenFocus);
37
         this.props.navigation.addListener('focus', this.onScreenFocus);
33
-        this.fetchedData = new Array(this.props.links.length);
34
-        this.errors = new Array(this.props.links.length);
38
+        this.fetchedData = new Array(this.props.requests.length);
39
+        this.errors = new Array(this.props.requests.length);
35
     }
40
     }
36
 
41
 
37
     /**
42
     /**
38
      * Refreshes screen if user changed
43
      * Refreshes screen if user changed
39
      */
44
      */
40
     onScreenFocus = () => {
45
     onScreenFocus = () => {
41
-        if (this.currentUserToken !== this.connectionManager.getToken()){
46
+        if (this.currentUserToken !== this.connectionManager.getToken()) {
42
             this.currentUserToken = this.connectionManager.getToken();
47
             this.currentUserToken = this.connectionManager.getToken();
43
             this.fetchData();
48
             this.fetchData();
44
         }
49
         }
55
         if (!this.state.loading)
60
         if (!this.state.loading)
56
             this.setState({loading: true});
61
             this.setState({loading: true});
57
         if (this.connectionManager.isLoggedIn()) {
62
         if (this.connectionManager.isLoggedIn()) {
58
-            for (let i = 0; i < this.props.links.length; i++) {
59
-                this.connectionManager.authenticatedRequest(this.props.links[i].link, null, null)
63
+            for (let i = 0; i < this.props.requests.length; i++) {
64
+                this.connectionManager.authenticatedRequest(
65
+                    this.props.requests[i].link,
66
+                    this.props.requests[i].params)
60
                     .then((data) => {
67
                     .then((data) => {
61
                         this.onRequestFinished(data, i, -1);
68
                         this.onRequestFinished(data, i, -1);
62
                     })
69
                     })
65
                     });
72
                     });
66
             }
73
             }
67
         } else {
74
         } else {
68
-            for (let i = 0; i < this.props.links.length; i++) {
75
+            for (let i = 0; i < this.props.requests.length; i++) {
69
                 this.onRequestFinished(null, i, ERROR_TYPE.BAD_TOKEN);
76
                 this.onRequestFinished(null, i, ERROR_TYPE.BAD_TOKEN);
70
             }
77
             }
71
         }
78
         }
82
      * @param error The error code received
89
      * @param error The error code received
83
      */
90
      */
84
     onRequestFinished(data: Object | null, index: number, error: number) {
91
     onRequestFinished(data: Object | null, index: number, error: number) {
85
-        if (index >= 0 && index < this.props.links.length){
92
+        if (index >= 0 && index < this.props.requests.length) {
86
             this.fetchedData[index] = data;
93
             this.fetchedData[index] = data;
87
             this.errors[index] = error;
94
             this.errors[index] = error;
88
         }
95
         }
120
     allRequestsValid() {
127
     allRequestsValid() {
121
         let valid = true;
128
         let valid = true;
122
         for (let i = 0; i < this.fetchedData.length; i++) {
129
         for (let i = 0; i < this.fetchedData.length; i++) {
123
-            if (this.fetchedData[i] === null && this.props.links[i].mandatory) {
130
+            if (this.fetchedData[i] === null && this.props.requests[i].mandatory) {
124
                 valid = false;
131
                 valid = false;
125
                 break;
132
                 break;
126
             }
133
             }
137
      */
144
      */
138
     getError() {
145
     getError() {
139
         for (let i = 0; i < this.errors.length; i++) {
146
         for (let i = 0; i < this.errors.length; i++) {
140
-            if (this.errors[i] !== 0 && this.props.links[i].mandatory) {
147
+            if (this.errors[i] !== 0 && this.props.requests[i].mandatory) {
141
                 return this.errors[i];
148
                 return this.errors[i];
142
             }
149
             }
143
         }
150
         }

+ 1
- 2
src/components/Amicale/Vote/VoteSelect.js View File

45
         return new Promise((resolve, reject) => {
45
         return new Promise((resolve, reject) => {
46
             ConnectionManager.getInstance().authenticatedRequest(
46
             ConnectionManager.getInstance().authenticatedRequest(
47
                 "elections/vote",
47
                 "elections/vote",
48
-                ["vote"],
49
-                [parseInt(this.state.selectedTeam)])
48
+                {"vote": parseInt(this.state.selectedTeam)})
50
                 .then(() => {
49
                 .then(() => {
51
                     this.onVoteDialogDismiss();
50
                     this.onVoteDialogDismiss();
52
                     this.props.onVoteSuccess();
51
                     this.props.onVoteSuccess();

+ 1
- 1
src/components/Custom/ErrorView.js View File

5
 import {StyleSheet, View} from "react-native";
5
 import {StyleSheet, View} from "react-native";
6
 import {MaterialCommunityIcons} from "@expo/vector-icons";
6
 import {MaterialCommunityIcons} from "@expo/vector-icons";
7
 import i18n from 'i18n-js';
7
 import i18n from 'i18n-js';
8
-import {ERROR_TYPE} from "../../managers/ConnectionManager";
8
+import {ERROR_TYPE} from "../../utils/WebData";
9
 
9
 
10
 type Props = {
10
 type Props = {
11
     navigation: Object,
11
     navigation: Object,

+ 1
- 2
src/components/Lists/WebSectionList.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import * as React from 'react';
3
 import * as React from 'react';
4
-import {readData} from "../../utils/WebData";
4
+import {ERROR_TYPE, readData} from "../../utils/WebData";
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 ErrorView from "../Custom/ErrorView";
8
 import ErrorView from "../Custom/ErrorView";
9
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
9
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
10
-import {ERROR_TYPE} from "../../managers/ConnectionManager";
11
 
10
 
12
 type Props = {
11
 type Props = {
13
     navigation: Object,
12
     navigation: Object,

+ 26
- 96
src/managers/ConnectionManager.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import * as SecureStore from 'expo-secure-store';
3
 import * as SecureStore from 'expo-secure-store';
4
-
5
-export const ERROR_TYPE = {
6
-    SUCCESS: 0,
7
-    BAD_CREDENTIALS: 1,
8
-    BAD_TOKEN: 2,
9
-    NO_CONSENT: 3,
10
-    BAD_INPUT: 400,
11
-    FORBIDDEN: 403,
12
-    CONNECTION_ERROR: 404,
13
-    SERVER_ERROR: 500,
14
-    UNKNOWN: 999,
15
-};
16
-
17
-type response_format = {
18
-    error: number,
19
-    data: Object,
20
-}
4
+import {apiRequest, ERROR_TYPE, isResponseValid} from "../utils/WebData";
21
 
5
 
22
 /**
6
 /**
23
  * champ: error
7
  * champ: error
30
  * 500 : SERVER_ERROR -> pb coté serveur
14
  * 500 : SERVER_ERROR -> pb coté serveur
31
  */
15
  */
32
 
16
 
33
-const API_ENDPOINT = "https://www.amicale-insat.fr/api/";
17
+
34
 const AUTH_PATH = "password";
18
 const AUTH_PATH = "password";
35
 
19
 
36
 export default class ConnectionManager {
20
 export default class ConnectionManager {
126
     }
110
     }
127
 
111
 
128
     async connect(email: string, password: string) {
112
     async connect(email: string, password: string) {
129
-        let data = {
130
-            email: email,
131
-            password: password,
132
-        };
133
         return new Promise((resolve, reject) => {
113
         return new Promise((resolve, reject) => {
134
-            fetch(API_ENDPOINT + AUTH_PATH, {
135
-                method: 'POST',
136
-                headers: new Headers({
137
-                    'Accept': 'application/json',
138
-                    'Content-Type': 'application/json',
139
-                }),
140
-                body: JSON.stringify(data)
141
-            }).then(async (response) => response.json())
142
-                .then((response: response_format) => {
143
-                    if (this.isConnectionResponseValid(response)) {
144
-                        if (response.error === ERROR_TYPE.SUCCESS) {
145
-                            this.saveLogin(email, response.data.token)
146
-                                .then(() => {
147
-                                    resolve(true);
148
-                                })
149
-                                .catch(() => {
150
-                                    reject(ERROR_TYPE.UNKNOWN);
151
-                                });
152
-                        } else
153
-                            reject(response.error);
154
-                    } else
155
-                        reject(ERROR_TYPE.CONNECTION_ERROR);
114
+            const data = {
115
+                email: email,
116
+                password: password,
117
+            };
118
+            apiRequest(AUTH_PATH, 'POST', data)
119
+                .then((response) => {
120
+                    this.saveLogin(email, response.token)
121
+                        .then(() => {
122
+                            resolve(true);
123
+                        })
124
+                        .catch(() => {
125
+                            reject(ERROR_TYPE.UNKNOWN);
126
+                        });
156
                 })
127
                 })
157
-                .catch((error) => {
158
-                    reject(ERROR_TYPE.CONNECTION_ERROR);
159
-                });
128
+                .catch((error) => reject(error));
160
         });
129
         });
161
     }
130
     }
162
 
131
 
163
-    isResponseValid(response: response_format) {
164
-        let valid = response !== undefined
165
-            && response.error !== undefined
166
-            && typeof response.error === "number";
167
-
168
-        valid = valid
169
-            && response.data !== undefined
170
-            && typeof response.data === "object";
171
-        return valid;
172
-    }
173
-
174
-    isConnectionResponseValid(response: response_format) {
175
-        let valid = this.isResponseValid(response);
132
+    isConnectionResponseValid(response: Object) {
133
+        let valid = isResponseValid(response);
176
 
134
 
177
         if (valid && response.error === ERROR_TYPE.SUCCESS)
135
         if (valid && response.error === ERROR_TYPE.SUCCESS)
178
             valid = valid
136
             valid = valid
182
         return valid;
140
         return valid;
183
     }
141
     }
184
 
142
 
185
-    generatePostArguments(keys: Array<string>, values: Array<string>) {
186
-        let data = {};
187
-        for (let i = 0; i < keys.length; i++) {
188
-            data[keys[i]] = values[i];
189
-        }
190
-        return data;
191
-    }
192
-
193
-    async authenticatedRequest(path: string, keys: Array<string>|null, values: Array<any>|null) {
143
+    async authenticatedRequest(path: string, params: Object) {
194
         return new Promise((resolve, reject) => {
144
         return new Promise((resolve, reject) => {
195
             if (this.getToken() !== null) {
145
             if (this.getToken() !== null) {
196
-                let data = {};
197
-                if (keys !== null && values !== null && keys.length === values.length)
198
-                    data = this.generatePostArguments(keys, values);
199
                 // console.log(data);
146
                 // console.log(data);
200
-                fetch(API_ENDPOINT + path, {
201
-                    method: 'POST',
202
-                    headers: new Headers({
203
-                        'Accept': 'application/json',
204
-                        'Content-Type': 'application/json',
205
-                    }),
206
-                    body: JSON.stringify({
207
-                        token: this.getToken(),
208
-                        ...data
209
-                    })
210
-                }).then(async (response) => response.json())
211
-                    .then((response: response_format) => {
212
-                        // console.log(response);
213
-                        if (this.isResponseValid(response)) {
214
-                            if (response.error === ERROR_TYPE.SUCCESS)
215
-                                resolve(response.data);
216
-                            else
217
-                                reject(response.error);
218
-                        } else
219
-                            reject(ERROR_TYPE.CONNECTION_ERROR);
220
-                    })
221
-                    .catch(() => {
222
-                        reject(ERROR_TYPE.CONNECTION_ERROR);
223
-                    });
147
+                let data = {
148
+                    token: this.getToken(),
149
+                    ...params
150
+                };
151
+                apiRequest(path, 'POST', data)
152
+                    .then((response) => resolve(response))
153
+                    .catch((error) => reject(error));
224
             } else
154
             } else
225
                 reject(ERROR_TYPE.UNKNOWN);
155
                 reject(ERROR_TYPE.UNKNOWN);
226
         });
156
         });

+ 7
- 25
src/screens/Amicale/Clubs/ClubDisplayScreen.js View File

22
     Linking.openURL(link).catch((err) => console.error('Error opening link', err));
22
     Linking.openURL(link).catch((err) => console.error('Error opening link', err));
23
 }
23
 }
24
 
24
 
25
-const FakeClub = {
26
-    "category": [
27
-        3,
28
-        6,
29
-    ],
30
-    "description": "<p class=\"ql-align-justify\">Les 100 Tours de l’INSA reviennent en force pour une cinquième édition les 5 et 6 juin prochain&nbsp;!</p><p class=\"ql-align-justify\"><br></p><p class=\"ql-align-justify\">Prépare-toi pour le plus gros évènement de l’année sur le campus de notre belle école qui nous réunit tous autour d’activités folles&nbsp;pour fêter la fin de l’année dans la bonne humeur !</p><p class=\"ql-align-justify\">L’éco-festival tournera autour d’une grande course par équipe qui nous vaut ce doux nom de 100 tours. Ce sera le moment de défier tes potes pour tenter de remporter de nombreux lots, et surtout l’admiration de tous. Mais cela ne s’arrête pas là, puisque tu pourras aussi participer à des activités à sensation, divers ateliers, et de quoi chiller avec tes potes en écoutant de la bonne musique. Tu pourras ensuite enchaîner sur LA soirée de l’année, rythmée par des artistes sur-motivés&nbsp;!</p><p class=\"ql-align-justify\"><br></p><p class=\"ql-align-justify\">Tu es bien entendu le bienvenu si l’envie te prend de rejoindre l’équipe et de nous aider à organiser cet évènement du turfu&nbsp;!</p><p class=\"ql-align-justify\"><br></p><p class=\"ql-align-justify\">La team 100 Tours</p><p class=\"ql-align-justify\"><br></p><p>Contact&nbsp;: <a href=\"mailto:100Tours@amicale-insat.fr\" target=\"_blank\">100tours@amicale-insat.fr</a></p><p>Facebook&nbsp;: Les 100 Tours de l’INSA</p><p>Instagram&nbsp;: 100tours.insatoulouse</p>",
31
-    "id": 110,
32
-    "logo": "https://www.amicale-insat.fr/storage/clubLogos/2cca8885dd3bdf902124f038b548962b.jpeg",
33
-    "name": "100 Tours",
34
-    "responsibles": [
35
-        "Juliette Duval",
36
-        "Emilie Cuminal",
37
-        "Maxime Doré",
38
-    ],
39
-};
40
-
41
 /**
25
 /**
42
  * Class defining a club event information page.
26
  * Class defining a club event information page.
43
  * If called with data and categories navigation parameters, will use those to display the data.
27
  * If called with data and categories navigation parameters, will use those to display the data.
132
         this.props.navigation.setOptions({title: data.name})
116
         this.props.navigation.setOptions({title: data.name})
133
     }
117
     }
134
 
118
 
135
-    getScreen = (data: Object) => {
136
-        console.log('fetchedData passed to screen:');
137
-        console.log(data);
138
-        console.log("Using fake data");
139
-        data = FakeClub;
119
+    getScreen = (response: Array<Object>) => {
120
+        let data = response[0];
140
         this.updateHeaderTitle(data);
121
         this.updateHeaderTitle(data);
141
 
122
 
142
         return (
123
         return (
182
         if (this.shouldFetchData)
163
         if (this.shouldFetchData)
183
             return <AuthenticatedScreen
164
             return <AuthenticatedScreen
184
                 {...this.props}
165
                 {...this.props}
185
-                links={[
166
+                requests={[
186
                     {
167
                     {
187
-                        link: 'clubs/' + this.clubId,
188
-                        mandatory: true,
168
+                        link: 'clubs/info',
169
+                        params: {'id': this.clubId},
170
+                        mandatory: true
189
                     }
171
                     }
190
                 ]}
172
                 ]}
191
                 renderFunction={this.getScreen}
173
                 renderFunction={this.getScreen}
192
             />;
174
             />;
193
         else
175
         else
194
-            return this.getScreen(this.displayData);
176
+            return this.getScreen([this.displayData]);
195
     }
177
     }
196
 }
178
 }
197
 
179
 

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

193
         return (
193
         return (
194
             <AuthenticatedScreen
194
             <AuthenticatedScreen
195
                 {...this.props}
195
                 {...this.props}
196
-                links={[
196
+                requests={[
197
                     {
197
                     {
198
                         link: 'clubs/list',
198
                         link: 'clubs/list',
199
+                        params: {},
199
                         mandatory: true,
200
                         mandatory: true,
200
                     }
201
                     }
201
                 ]}
202
                 ]}

+ 6
- 10
src/screens/Amicale/ProfileScreen.js View File

265
      * @return {*}
265
      * @return {*}
266
      */
266
      */
267
     clubListItem = ({item}: Object) => {
267
     clubListItem = ({item}: Object) => {
268
-        const onPress = () => this.openClubDetailsScreen(0); // TODO get club id
269
-        const isManager = false; // TODO detect if manager
268
+        const onPress = () => this.openClubDetailsScreen(item.id);
270
         let description = i18n.t("profileScreen.isMember");
269
         let description = i18n.t("profileScreen.isMember");
271
         let icon = (props) => <List.Icon {...props} icon="chevron-right"/>;
270
         let icon = (props) => <List.Icon {...props} icon="chevron-right"/>;
272
-        if (isManager) {
271
+        if (item.is_manager) {
273
             description = i18n.t("profileScreen.isManager");
272
             description = i18n.t("profileScreen.isManager");
274
             icon = (props) => <List.Icon {...props} icon="star" color={this.colors.primary}/>;
273
             icon = (props) => <List.Icon {...props} icon="star" color={this.colors.primary}/>;
275
         }
274
         }
289
      * @param list The club list
288
      * @param list The club list
290
      * @return {*}
289
      * @return {*}
291
      */
290
      */
292
-    getClubList(list: Array<string>) {
293
-        let dataset = [];
294
-        for (let i = 0; i < list.length; i++) {
295
-            dataset.push({name: list[i]});
296
-        }
291
+    getClubList(list: Array<Object>) {
297
         return (
292
         return (
298
             //$FlowFixMe
293
             //$FlowFixMe
299
             <FlatList
294
             <FlatList
300
                 renderItem={this.clubListItem}
295
                 renderItem={this.clubListItem}
301
                 keyExtractor={this.clubKeyExtractor}
296
                 keyExtractor={this.clubKeyExtractor}
302
-                data={dataset}
297
+                data={list}
303
             />
298
             />
304
         );
299
         );
305
     }
300
     }
308
         return (
303
         return (
309
             <AuthenticatedScreen
304
             <AuthenticatedScreen
310
                 {...this.props}
305
                 {...this.props}
311
-                links={[
306
+                requests={[
312
                     {
307
                     {
313
                         link: 'user/profile',
308
                         link: 'user/profile',
309
+                        params: {},
314
                         mandatory: true,
310
                         mandatory: true,
315
                     }
311
                     }
316
                 ]}
312
                 ]}

+ 3
- 1
src/screens/Amicale/VoteScreen.js View File

216
             <AuthenticatedScreen
216
             <AuthenticatedScreen
217
                 {...this.props}
217
                 {...this.props}
218
                 ref={this.authRef}
218
                 ref={this.authRef}
219
-                links={[
219
+                requests={[
220
                     {
220
                     {
221
                         link: 'elections/teams',
221
                         link: 'elections/teams',
222
+                        params: {},
222
                         mandatory: false,
223
                         mandatory: false,
223
                     },
224
                     },
224
                     {
225
                     {
225
                         link: 'elections/datesString',
226
                         link: 'elections/datesString',
227
+                        params: {},
226
                         mandatory: false,
228
                         mandatory: false,
227
                     },
229
                     },
228
                 ]}
230
                 ]}

+ 47
- 20
src/screens/Planning/PlanningDisplayScreen.js View File

8
 import {Card, withTheme} from 'react-native-paper';
8
 import {Card, withTheme} from 'react-native-paper';
9
 import DateManager from "../../managers/DateManager";
9
 import DateManager from "../../managers/DateManager";
10
 import ImageModal from 'react-native-image-modal';
10
 import ImageModal from 'react-native-image-modal';
11
+import BasicLoadingScreen from "../../components/Custom/BasicLoadingScreen";
12
+import {apiRequest} from "../../utils/WebData";
13
+import ErrorView from "../../components/Custom/ErrorView";
11
 
14
 
12
 type Props = {
15
 type Props = {
13
     navigation: Object,
16
     navigation: Object,
15
 };
18
 };
16
 
19
 
17
 type State = {
20
 type State = {
21
+    loading: boolean
18
 };
22
 };
19
 
23
 
20
 function openWebLink(event, link) {
24
 function openWebLink(event, link) {
21
     Linking.openURL(link).catch((err) => console.error('Error opening link', err));
25
     Linking.openURL(link).catch((err) => console.error('Error opening link', err));
22
 }
26
 }
23
 
27
 
24
-const FAKE_EVENT = {
25
-    "id": 142,
26
-    "title": "Soir\u00e9e Impact'INSA",
27
-    "logo": null,
28
-    "date_begin": "2020-04-22 19:00",
29
-    "date_end": "2020-04-22 00:00",
30
-    "description": "<p>R\u00e9servation salle de boom + PK pour la soir\u00e9e Impact'Insa<\/p>",
31
-    "club": "Impact Insa",
32
-    "category_id": 10,
33
-    "url": "https:\/\/www.amicale-insat.fr\/event\/142\/view"
34
-};
28
+const CLUB_INFO_PATH = "event/info";
35
 
29
 
36
 /**
30
 /**
37
  * Class defining a planning event information page.
31
  * Class defining a planning event information page.
41
     displayData: Object;
35
     displayData: Object;
42
     shouldFetchData: boolean;
36
     shouldFetchData: boolean;
43
     eventId: number;
37
     eventId: number;
38
+    errorCode: number;
44
 
39
 
45
     colors: Object;
40
     colors: Object;
46
 
41
 
47
-    state = {
48
-
49
-    };
50
-
51
     constructor(props) {
42
     constructor(props) {
52
         super(props);
43
         super(props);
53
         this.colors = props.theme.colors;
44
         this.colors = props.theme.colors;
54
 
45
 
55
         if (this.props.route.params.data !== undefined) {
46
         if (this.props.route.params.data !== undefined) {
56
             this.displayData = this.props.route.params.data;
47
             this.displayData = this.props.route.params.data;
57
-            this.eventId = this.props.route.params.data.eventId;
48
+            console.log(this.displayData);
49
+            this.eventId = this.displayData.id;
58
             this.shouldFetchData = false;
50
             this.shouldFetchData = false;
51
+            this.errorCode = 0;
52
+            this.state = {
53
+                loading: false,
54
+            };
59
         } else {
55
         } else {
60
-            this.displayData = FAKE_EVENT;
56
+            this.displayData = null;
61
             this.eventId = this.props.route.params.eventId;
57
             this.eventId = this.props.route.params.eventId;
62
             this.shouldFetchData = true;
58
             this.shouldFetchData = true;
63
-            console.log(this.eventId);
59
+            this.errorCode = 0;
60
+            this.state = {
61
+                loading: true,
62
+            };
63
+            this.fetchData();
64
+
64
         }
65
         }
65
     }
66
     }
66
 
67
 
67
-    render() {
68
-        // console.log("rendering planningDisplayScreen");
68
+    fetchData = () => {
69
+        this.setState({loading: true});
70
+        apiRequest(CLUB_INFO_PATH, 'POST', {id: this.eventId})
71
+            .then(this.onFetchSuccess)
72
+            .catch(this.onFetchError);
73
+    };
74
+
75
+    onFetchSuccess = (data: Object) => {
76
+        this.displayData = data;
77
+        console.log(this.displayData);
78
+        this.setState({loading: false});
79
+    };
80
+
81
+    onFetchError = (error: number) => {
82
+        this.errorCode = error;
83
+        this.setState({loading: false});
84
+    };
85
+
86
+    getContent() {
69
         let subtitle = getFormattedEventTime(
87
         let subtitle = getFormattedEventTime(
70
             this.displayData["date_begin"], this.displayData["date_end"]);
88
             this.displayData["date_begin"], this.displayData["date_end"]);
71
         let dateString = getDateOnlyString(this.displayData["date_begin"]);
89
         let dateString = getDateOnlyString(this.displayData["date_begin"]);
106
             </ScrollView>
124
             </ScrollView>
107
         );
125
         );
108
     }
126
     }
127
+
128
+    render() {
129
+        if (this.state.loading)
130
+            return <BasicLoadingScreen/>;
131
+        else if (this.errorCode === 0)
132
+            return this.getContent();
133
+        else
134
+            return <ErrorView {...this.props} errorCode={this.errorCode}   onRefresh={this.fetchData}/>;
135
+    }
109
 }
136
 }
110
 
137
 
111
 export default withTheme(PlanningDisplayScreen);
138
 export default withTheme(PlanningDisplayScreen);

+ 60
- 0
src/utils/WebData.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
+export const ERROR_TYPE = {
4
+    SUCCESS: 0,
5
+    BAD_CREDENTIALS: 1,
6
+    BAD_TOKEN: 2,
7
+    NO_CONSENT: 3,
8
+    BAD_INPUT: 400,
9
+    FORBIDDEN: 403,
10
+    CONNECTION_ERROR: 404,
11
+    SERVER_ERROR: 500,
12
+    UNKNOWN: 999,
13
+};
14
+
15
+type response_format = {
16
+    error: number,
17
+    data: Object,
18
+}
19
+
20
+const API_ENDPOINT = "https://www.amicale-insat.fr/api/";
21
+
22
+export async function apiRequest(path: string, method: string, params: ?Object) {
23
+    if (params === undefined || params === null)
24
+        params = {};
25
+
26
+    return new Promise((resolve, reject) => {
27
+        fetch(API_ENDPOINT + path, {
28
+            method: method,
29
+            headers: new Headers({
30
+                'Accept': 'application/json',
31
+                'Content-Type': 'application/json',
32
+            }),
33
+            body: JSON.stringify({
34
+                ...params
35
+            })
36
+        }).then(async (response) => response.json())
37
+            .then((response: response_format) => {
38
+                if (isResponseValid(response)) {
39
+                    if (response.error === ERROR_TYPE.SUCCESS)
40
+                        resolve(response.data);
41
+                    else
42
+                        reject(response.error);
43
+                } else
44
+                    reject(ERROR_TYPE.CONNECTION_ERROR);
45
+            })
46
+            .catch(() => {
47
+                reject(ERROR_TYPE.CONNECTION_ERROR);
48
+            });
49
+    });
50
+}
51
+
52
+export function isResponseValid(response: response_format) {
53
+    let valid = response !== undefined
54
+        && response.error !== undefined
55
+        && typeof response.error === "number";
56
+
57
+    valid = valid
58
+        && response.data !== undefined
59
+        && typeof response.data === "object";
60
+    return valid;
61
+}
62
+
3
 /**
63
 /**
4
  * Read data from FETCH_URL and return it.
64
  * Read data from FETCH_URL and return it.
5
  * If no data was found, returns an empty object
65
  * If no data was found, returns an empty object

Loading…
Cancel
Save