Browse Source

Update utility files to use TypeScript

Arnaud Vergnet 3 years ago
parent
commit
18ec6e0a59

+ 16
- 0
package-lock.json View File

@@ -2501,6 +2501,12 @@
2501 2501
       "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.36.tgz",
2502 2502
       "integrity": "sha512-7TUK/k2/QGpEAv/BCwSHlYu3NXZhQ9ZwBYpzr9tjlPIL2C5BeGhH3DmVavRx3ZNyELX5TLC91JTz/cen6AAtIQ=="
2503 2503
     },
2504
+    "@types/i18n-js": {
2505
+      "version": "3.0.3",
2506
+      "resolved": "https://registry.npmjs.org/@types/i18n-js/-/i18n-js-3.0.3.tgz",
2507
+      "integrity": "sha512-GiZzazvxQ5j+EA4Zf4MtDsSaokAR/gW7FxxTlHi2p2xKFUhwAUT0B/MB8WL77P1TcqAO3MefWorFFyZS8F7s0Q==",
2508
+      "dev": true
2509
+    },
2504 2510
     "@types/istanbul-lib-coverage": {
2505 2511
       "version": "2.0.3",
2506 2512
       "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -2602,6 +2608,16 @@
2602 2608
         "@types/react": "*"
2603 2609
       }
2604 2610
     },
2611
+    "@types/react-native-vector-icons": {
2612
+      "version": "6.4.6",
2613
+      "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.6.tgz",
2614
+      "integrity": "sha512-lAyxNfMd5L1xZvXWsGcJmNegDf61TAp40uL6ashNNWj9W3IrDJO59L9+9inh0Y2MsEZpLTdxzVU8Unb4/0FQng==",
2615
+      "dev": true,
2616
+      "requires": {
2617
+        "@types/react": "*",
2618
+        "@types/react-native": "*"
2619
+      }
2620
+    },
2605 2621
     "@types/react-test-renderer": {
2606 2622
       "version": "16.9.3",
2607 2623
       "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-16.9.3.tgz",

+ 2
- 0
package.json View File

@@ -66,6 +66,8 @@
66 66
     "@babel/core": "^7.11.0",
67 67
     "@babel/runtime": "^7.11.0",
68 68
     "@react-native-community/eslint-config": "^1.1.0",
69
+    "@types/i18n-js": "^3.0.3",
70
+    "@types/react-native-vector-icons": "^6.4.6",
69 71
     "@types/jest": "^25.2.3",
70 72
     "@types/react-native": "^0.63.2",
71 73
     "@types/react-test-renderer": "^16.9.2",

src/managers/AprilFoolsManager.js → src/managers/AprilFoolsManager.ts View File

@@ -17,10 +17,7 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import type {ProxiwashMachineType} from '../screens/Proxiwash/ProxiwashScreen';
23
-import type {CustomThemeType} from './ThemeManager';
24 21
 import type {RuFoodCategoryType} from '../screens/Services/SelfMenuScreen';
25 22
 
26 23
 /**
@@ -57,8 +54,9 @@ export default class AprilFoolsManager {
57 54
    * @returns {ThemeManager}
58 55
    */
59 56
   static getInstance(): AprilFoolsManager {
60
-    if (AprilFoolsManager.instance == null)
57
+    if (AprilFoolsManager.instance == null) {
61 58
       AprilFoolsManager.instance = new AprilFoolsManager();
59
+    }
62 60
     return AprilFoolsManager.instance;
63 61
   }
64 62
 
@@ -130,7 +128,9 @@ export default class AprilFoolsManager {
130 128
    * @param currentTheme
131 129
    * @returns {{colors: {textDisabled: string, agendaDayTextColor: string, surface: string, background: string, dividerBackground: string, accent: string, agendaBackgroundColor: string, tabIcon: string, card: string, primary: string}}}
132 130
    */
133
-  static getAprilFoolsTheme(currentTheme: CustomThemeType): CustomThemeType {
131
+  static getAprilFoolsTheme(
132
+    currentTheme: ReactNativePaper.Theme,
133
+  ): ReactNativePaper.Theme {
134 134
     return {
135 135
       ...currentTheme,
136 136
       colors: {

+ 1
- 1
src/managers/AsyncStorageManager.ts View File

@@ -198,7 +198,7 @@ export default class AsyncStorageManager {
198 198
    * @param key
199 199
    * @returns {{...}}
200 200
    */
201
-  static getObject(key: string): object | Array<any> {
201
+  static getObject<T>(key: string): T {
202 202
     return JSON.parse(AsyncStorageManager.getString(key));
203 203
   }
204 204
 

src/managers/ConnectionManager.js → src/managers/ConnectionManager.ts View File

@@ -20,7 +20,7 @@
20 20
 // @flow
21 21
 
22 22
 import * as Keychain from 'react-native-keychain';
23
-import type {ApiDataLoginType, ApiGenericDataType} from '../utils/WebData';
23
+import type {ApiDataLoginType} from '../utils/WebData';
24 24
 import {apiRequest, ERROR_TYPE} from '../utils/WebData';
25 25
 
26 26
 /**
@@ -40,12 +40,10 @@ const AUTH_PATH = 'password';
40 40
 export default class ConnectionManager {
41 41
   static instance: ConnectionManager | null = null;
42 42
 
43
-  #email: string;
44
-
45
-  #token: string | null;
43
+  private token: string | null;
46 44
 
47 45
   constructor() {
48
-    this.#token = null;
46
+    this.token = null;
49 47
   }
50 48
 
51 49
   /**
@@ -54,8 +52,9 @@ export default class ConnectionManager {
54 52
    * @returns {ConnectionManager}
55 53
    */
56 54
   static getInstance(): ConnectionManager {
57
-    if (ConnectionManager.instance == null)
55
+    if (ConnectionManager.instance == null) {
58 56
       ConnectionManager.instance = new ConnectionManager();
57
+    }
59 58
     return ConnectionManager.instance;
60 59
   }
61 60
 
@@ -65,7 +64,7 @@ export default class ConnectionManager {
65 64
    * @returns {string | null}
66 65
    */
67 66
   getToken(): string | null {
68
-    return this.#token;
67
+    return this.token;
69 68
   }
70 69
 
71 70
   /**
@@ -77,18 +76,17 @@ export default class ConnectionManager {
77 76
     return new Promise(
78 77
       (resolve: (token: string) => void, reject: () => void) => {
79 78
         const token = this.getToken();
80
-        if (token != null) resolve(token);
81
-        else {
79
+        if (token != null) {
80
+          resolve(token);
81
+        } else {
82 82
           Keychain.getInternetCredentials(SERVER_NAME)
83 83
             .then((data: Keychain.UserCredentials | false) => {
84
-              if (
85
-                data != null &&
86
-                data.password != null &&
87
-                typeof data.password === 'string'
88
-              ) {
89
-                this.#token = data.password;
90
-                resolve(this.#token);
91
-              } else reject();
84
+              if (data && data.password != null) {
85
+                this.token = data.password;
86
+                resolve(this.token);
87
+              } else {
88
+                reject();
89
+              }
92 90
             })
93 91
             .catch((): void => reject());
94 92
         }
@@ -116,8 +114,7 @@ export default class ConnectionManager {
116 114
     return new Promise((resolve: () => void, reject: () => void) => {
117 115
       Keychain.setInternetCredentials(SERVER_NAME, 'token', token)
118 116
         .then(() => {
119
-          this.#token = token;
120
-          this.#email = email;
117
+          this.token = token;
121 118
           resolve();
122 119
         })
123 120
         .catch((): void => reject());
@@ -133,7 +130,7 @@ export default class ConnectionManager {
133 130
     return new Promise((resolve: () => void, reject: () => void) => {
134 131
       Keychain.resetInternetCredentials(SERVER_NAME)
135 132
         .then(() => {
136
-          this.#token = null;
133
+          this.token = null;
137 134
           resolve();
138 135
         })
139 136
         .catch((): void => reject());
@@ -156,13 +153,15 @@ export default class ConnectionManager {
156 153
           email,
157 154
           password,
158 155
         };
159
-        apiRequest(AUTH_PATH, 'POST', data)
156
+        apiRequest<ApiDataLoginType>(AUTH_PATH, 'POST', data)
160 157
           .then((response: ApiDataLoginType) => {
161 158
             if (response.token != null) {
162 159
               this.saveLogin(email, response.token)
163 160
                 .then((): void => resolve())
164 161
                 .catch((): void => reject(ERROR_TYPE.TOKEN_SAVE));
165
-            } else reject(ERROR_TYPE.SERVER_ERROR);
162
+            } else {
163
+              reject(ERROR_TYPE.SERVER_ERROR);
164
+            }
166 165
           })
167 166
           .catch((error: number): void => reject(error));
168 167
       },
@@ -176,24 +175,23 @@ export default class ConnectionManager {
176 175
    * @param params
177 176
    * @returns Promise<ApiGenericDataType>
178 177
    */
179
-  async authenticatedRequest(
178
+  async authenticatedRequest<T>(
180 179
     path: string,
181
-    params: {...},
182
-  ): Promise<ApiGenericDataType> {
180
+    params: {[key: string]: any},
181
+  ): Promise<T> {
183 182
     return new Promise(
184
-      (
185
-        resolve: (response: ApiGenericDataType) => void,
186
-        reject: (error: number) => void,
187
-      ) => {
183
+      (resolve: (response: T) => void, reject: (error: number) => void) => {
188 184
         if (this.getToken() !== null) {
189 185
           const data = {
190 186
             ...params,
191 187
             token: this.getToken(),
192 188
           };
193
-          apiRequest(path, 'POST', data)
194
-            .then((response: ApiGenericDataType): void => resolve(response))
189
+          apiRequest<T>(path, 'POST', data)
190
+            .then((response: T): void => resolve(response))
195 191
             .catch((error: number): void => reject(error));
196
-        } else reject(ERROR_TYPE.TOKEN_RETRIEVE);
192
+        } else {
193
+          reject(ERROR_TYPE.TOKEN_RETRIEVE);
194
+        }
197 195
       },
198 196
     );
199 197
   }

src/managers/DashboardManager.js → src/managers/DashboardManager.ts View File

@@ -21,12 +21,12 @@
21 21
 
22 22
 import type {ServiceItemType} from './ServicesManager';
23 23
 import ServicesManager from './ServicesManager';
24
-import {getSublistWithIds} from '../utils/Utils';
24
+import {getSublistWithIds} from '../utils/Services';
25 25
 import AsyncStorageManager from './AsyncStorageManager';
26 26
 
27 27
 export default class DashboardManager extends ServicesManager {
28 28
   getCurrentDashboard(): Array<ServiceItemType | null> {
29
-    const dashboardIdList = AsyncStorageManager.getObject(
29
+    const dashboardIdList = AsyncStorageManager.getObject<Array<string>>(
30 30
       AsyncStorageManager.PREFERENCES.dashboardItems.key,
31 31
     );
32 32
     const allDatasets = [

src/managers/DateManager.js → src/managers/DateManager.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import i18n from 'i18n-js';
23 21
 
24 22
 /**
@@ -28,9 +26,9 @@ import i18n from 'i18n-js';
28 26
 export default class DateManager {
29 27
   static instance: DateManager | null = null;
30 28
 
31
-  daysOfWeek = [];
29
+  daysOfWeek: Array<string> = [];
32 30
 
33
-  monthsOfYear = [];
31
+  monthsOfYear: Array<string> = [];
34 32
 
35 33
   constructor() {
36 34
     this.daysOfWeek.push(i18n.t('date.daysOfWeek.sunday')); // 0 represents sunday
@@ -60,7 +58,9 @@ export default class DateManager {
60 58
    * @returns {DateManager}
61 59
    */
62 60
   static getInstance(): DateManager {
63
-    if (DateManager.instance == null) DateManager.instance = new DateManager();
61
+    if (DateManager.instance == null) {
62
+      DateManager.instance = new DateManager();
63
+    }
64 64
     return DateManager.instance;
65 65
   }
66 66
 

src/managers/ServicesManager.js → src/managers/ServicesManager.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import i18n from 'i18n-js';
23 21
 import {StackNavigationProp} from '@react-navigation/stack';
24 22
 import AvailableWebsites from '../constants/AvailableWebsites';
@@ -93,24 +91,24 @@ export const SERVICES_CATEGORIES_KEY = {
93 91
 };
94 92
 
95 93
 export type ServiceItemType = {
96
-  key: string,
97
-  title: string,
98
-  subtitle: string,
99
-  image: string,
100
-  onPress: () => void,
101
-  badgeFunction?: (dashboard: FullDashboardType) => number,
94
+  key: string;
95
+  title: string;
96
+  subtitle: string;
97
+  image: string;
98
+  onPress: () => void;
99
+  badgeFunction?: (dashboard: FullDashboardType) => number;
102 100
 };
103 101
 
104 102
 export type ServiceCategoryType = {
105
-  key: string,
106
-  title: string,
107
-  subtitle: string,
108
-  image: string | number,
109
-  content: Array<ServiceItemType>,
103
+  key: string;
104
+  title: string;
105
+  subtitle: string;
106
+  image: string | number;
107
+  content: Array<ServiceItemType>;
110 108
 };
111 109
 
112 110
 export default class ServicesManager {
113
-  navigation: StackNavigationProp;
111
+  navigation: StackNavigationProp<any>;
114 112
 
115 113
   amicaleDataset: Array<ServiceItemType>;
116 114
 
@@ -122,7 +120,7 @@ export default class ServicesManager {
122 120
 
123 121
   categoriesDataset: Array<ServiceCategoryType>;
124 122
 
125
-  constructor(nav: StackNavigationProp) {
123
+  constructor(nav: StackNavigationProp<any>) {
126 124
     this.navigation = nav;
127 125
     this.amicaleDataset = [
128 126
       {
@@ -336,9 +334,11 @@ export default class ServicesManager {
336 334
    * @returns {null}
337 335
    */
338 336
   onAmicaleServicePress(route: string) {
339
-    if (ConnectionManager.getInstance().isLoggedIn())
337
+    if (ConnectionManager.getInstance().isLoggedIn()) {
340 338
       this.navigation.navigate(route);
341
-    else this.navigation.navigate('login', {nextScreen: route});
339
+    } else {
340
+      this.navigation.navigate('login', {nextScreen: route});
341
+    }
342 342
   }
343 343
 
344 344
   /**
@@ -348,8 +348,9 @@ export default class ServicesManager {
348 348
    * @returns {Array<ServiceItemType>}
349 349
    */
350 350
   getAmicaleServices(excludedItems?: Array<string>): Array<ServiceItemType> {
351
-    if (excludedItems != null)
351
+    if (excludedItems != null) {
352 352
       return getStrippedServicesList(excludedItems, this.amicaleDataset);
353
+    }
353 354
     return this.amicaleDataset;
354 355
   }
355 356
 
@@ -360,8 +361,9 @@ export default class ServicesManager {
360 361
    * @returns {Array<ServiceItemType>}
361 362
    */
362 363
   getStudentServices(excludedItems?: Array<string>): Array<ServiceItemType> {
363
-    if (excludedItems != null)
364
+    if (excludedItems != null) {
364 365
       return getStrippedServicesList(excludedItems, this.studentsDataset);
366
+    }
365 367
     return this.studentsDataset;
366 368
   }
367 369
 
@@ -372,8 +374,9 @@ export default class ServicesManager {
372 374
    * @returns {Array<ServiceItemType>}
373 375
    */
374 376
   getINSAServices(excludedItems?: Array<string>): Array<ServiceItemType> {
375
-    if (excludedItems != null)
377
+    if (excludedItems != null) {
376 378
       return getStrippedServicesList(excludedItems, this.insaDataset);
379
+    }
377 380
     return this.insaDataset;
378 381
   }
379 382
 
@@ -384,8 +387,9 @@ export default class ServicesManager {
384 387
    * @returns {Array<ServiceItemType>}
385 388
    */
386 389
   getSpecialServices(excludedItems?: Array<string>): Array<ServiceItemType> {
387
-    if (excludedItems != null)
390
+    if (excludedItems != null) {
388 391
       return getStrippedServicesList(excludedItems, this.specialDataset);
392
+    }
389 393
     return this.specialDataset;
390 394
   }
391 395
 
@@ -396,8 +400,9 @@ export default class ServicesManager {
396 400
    * @returns {Array<ServiceCategoryType>}
397 401
    */
398 402
   getCategories(excludedItems?: Array<string>): Array<ServiceCategoryType> {
399
-    if (excludedItems != null)
403
+    if (excludedItems != null) {
400 404
       return getStrippedServicesList(excludedItems, this.categoriesDataset);
405
+    }
401 406
     return this.categoriesDataset;
402 407
   }
403 408
 }

src/utils/AutoHideHandler.js → src/utils/AutoHideHandler.ts View File

@@ -17,22 +17,12 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
20
+import {NativeScrollEvent, NativeSyntheticEvent} from 'react-native';
21 21
 
22 22
 const speedOffset = 5;
23 23
 
24 24
 type ListenerFunctionType = (shouldHide: boolean) => void;
25 25
 
26
-export type OnScrollType = {
27
-  nativeEvent: {
28
-    contentInset: {bottom: number, left: number, right: number, top: number},
29
-    contentOffset: {x: number, y: number},
30
-    contentSize: {height: number, width: number},
31
-    layoutMeasurement: {height: number, width: number},
32
-    zoomScale: number,
33
-  },
34
-};
35
-
36 26
 /**
37 27
  * Class used to detect when to show or hide a component based on scrolling
38 28
  */
@@ -46,6 +36,7 @@ export default class AutoHideHandler {
46 36
   constructor(startHidden: boolean) {
47 37
     this.listeners = [];
48 38
     this.isHidden = startHidden;
39
+    this.lastOffset = 0;
49 40
   }
50 41
 
51 42
   /**
@@ -84,7 +75,7 @@ export default class AutoHideHandler {
84 75
    *
85 76
    * @param event The scroll event generated by the animated component onScroll prop
86 77
    */
87
-  onScroll(event: OnScrollType) {
78
+  onScroll(event: NativeSyntheticEvent<NativeScrollEvent>) {
88 79
     const {nativeEvent} = event;
89 80
     const speed =
90 81
       nativeEvent.contentOffset.y < 0

src/utils/CollapsibleUtils.js → src/utils/CollapsibleUtils.tsx View File

@@ -17,12 +17,20 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import * as React from 'react';
23 21
 import {useTheme} from 'react-native-paper';
24 22
 import {createCollapsibleStack} from 'react-navigation-collapsible';
25 23
 import StackNavigator, {StackNavigationOptions} from '@react-navigation/stack';
24
+import {StackNavigationState} from '@react-navigation/native';
25
+import {StackNavigationEventMap} from '@react-navigation/stack/lib/typescript/src/types';
26
+
27
+type StackNavigatorType = import('@react-navigation/native').TypedNavigator<
28
+  Record<string, object | undefined>,
29
+  StackNavigationState,
30
+  StackNavigationOptions,
31
+  StackNavigationEventMap,
32
+  typeof StackNavigator
33
+>;
26 34
 
27 35
 /**
28 36
  * Creates a navigation stack with the collapsible library, allowing the header to collapse on scroll.
@@ -40,18 +48,16 @@ import StackNavigator, {StackNavigationOptions} from '@react-navigation/stack';
40 48
  * @param headerColor The color of the header. Uses default color if not specified
41 49
  * @returns {JSX.Element}
42 50
  */
43
-export function createScreenCollapsibleStack(
51
+export function CreateScreenCollapsibleStack(
44 52
   name: string,
45
-  Stack: StackNavigator,
46
-  // eslint-disable-next-line flowtype/no-weak-types
53
+  Stack: StackNavigatorType,
47 54
   component: React.ComponentType<any>,
48 55
   title: string,
49
-  useNativeDriver?: boolean,
50
-  options?: StackNavigationOptions,
56
+  useNativeDriver: boolean = true,
57
+  options: StackNavigationOptions = {},
51 58
   headerColor?: string,
52
-): React.Node {
59
+) {
53 60
   const {colors} = useTheme();
54
-  const screenOptions = options != null ? options : {};
55 61
   return createCollapsibleStack(
56 62
     <Stack.Screen
57 63
       name={name}
@@ -61,12 +67,12 @@ export function createScreenCollapsibleStack(
61 67
         headerStyle: {
62 68
           backgroundColor: headerColor != null ? headerColor : colors.surface,
63 69
         },
64
-        ...screenOptions,
70
+        ...options,
65 71
       }}
66 72
     />,
67 73
     {
68 74
       collapsedColor: headerColor != null ? headerColor : colors.surface,
69
-      useNativeDriver: useNativeDriver != null ? useNativeDriver : true, // native driver does not work with webview
75
+      useNativeDriver: useNativeDriver, // native driver does not work with webview
70 76
     },
71 77
   );
72 78
 }
@@ -85,10 +91,9 @@ export function createScreenCollapsibleStack(
85 91
  */
86 92
 export function getWebsiteStack(
87 93
   name: string,
88
-  Stack: StackNavigator,
89
-  // eslint-disable-next-line flowtype/no-weak-types
94
+  Stack: StackNavigatorType,
90 95
   component: React.ComponentType<any>,
91 96
   title: string,
92
-): React.Node {
93
-  return createScreenCollapsibleStack(name, Stack, component, title, false);
97
+) {
98
+  return CreateScreenCollapsibleStack(name, Stack, component, title, false);
94 99
 }

src/utils/EquipmentBooking.js → src/utils/EquipmentBooking.ts View File

@@ -17,12 +17,9 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import i18n from 'i18n-js';
23 21
 import type {DeviceType} from '../screens/Amicale/Equipment/EquipmentListScreen';
24 22
 import DateManager from '../managers/DateManager';
25
-import type {CustomThemeType} from '../managers/ThemeManager';
26 23
 import type {MarkedDatesObjectType} from '../screens/Amicale/Equipment/EquipmentRentScreen';
27 24
 
28 25
 /**
@@ -56,10 +53,12 @@ export function isEquipmentAvailable(item: DeviceType): boolean {
56 53
   let isAvailable = true;
57 54
   const today = getCurrentDay();
58 55
   const dates = item.booked_at;
59
-  dates.forEach((date: {begin: string, end: string}) => {
56
+  dates.forEach((date: {begin: string; end: string}) => {
60 57
     const start = new Date(date.begin);
61 58
     const end = new Date(date.end);
62
-    if (!(today < start || today > end)) isAvailable = false;
59
+    if (!(today < start || today > end)) {
60
+      isAvailable = false;
61
+    }
63 62
   });
64 63
   return isAvailable;
65 64
 }
@@ -73,11 +72,13 @@ export function isEquipmentAvailable(item: DeviceType): boolean {
73 72
 export function getFirstEquipmentAvailability(item: DeviceType): Date {
74 73
   let firstAvailability = getCurrentDay();
75 74
   const dates = item.booked_at;
76
-  dates.forEach((date: {begin: string, end: string}) => {
75
+  dates.forEach((date: {begin: string; end: string}) => {
77 76
     const start = new Date(date.begin);
78 77
     const end = new Date(date.end);
79 78
     end.setDate(end.getDate() + 1);
80
-    if (firstAvailability >= start) firstAvailability = end;
79
+    if (firstAvailability >= start) {
80
+      firstAvailability = end;
81
+    }
81 82
   });
82 83
   return firstAvailability;
83 84
 }
@@ -93,23 +94,24 @@ export function getRelativeDateString(date: Date): string {
93 94
   const monthDelta = date.getUTCMonth() - today.getUTCMonth();
94 95
   const dayDelta = date.getUTCDate() - today.getUTCDate();
95 96
   let translatedString = i18n.t('screens.equipment.today');
96
-  if (yearDelta > 0)
97
+  if (yearDelta > 0) {
97 98
     translatedString = i18n.t('screens.equipment.otherYear', {
98 99
       date: date.getDate(),
99 100
       month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
100 101
       year: date.getFullYear(),
101 102
     });
102
-  else if (monthDelta > 0)
103
+  } else if (monthDelta > 0) {
103 104
     translatedString = i18n.t('screens.equipment.otherMonth', {
104 105
       date: date.getDate(),
105 106
       month: DateManager.getInstance().getMonthsOfYear()[date.getMonth()],
106 107
     });
107
-  else if (dayDelta > 1)
108
+  } else if (dayDelta > 1) {
108 109
     translatedString = i18n.t('screens.equipment.thisMonth', {
109 110
       date: date.getDate(),
110 111
     });
111
-  else if (dayDelta === 1)
112
+  } else if (dayDelta === 1) {
112 113
     translatedString = i18n.t('screens.equipment.tomorrow');
114
+  }
113 115
 
114 116
   return translatedString;
115 117
 }
@@ -162,8 +164,11 @@ export function getValidRange(
162 164
     (direction === 1 && date < limit) ||
163 165
     (direction === -1 && date > limit)
164 166
   ) {
165
-    if (direction === 1) validRange.push(getISODate(date));
166
-    else validRange.unshift(getISODate(date));
167
+    if (direction === 1) {
168
+      validRange.push(getISODate(date));
169
+    } else {
170
+      validRange.unshift(getISODate(date));
171
+    }
167 172
     date.setDate(date.getDate() + direction);
168 173
   }
169 174
   return validRange;
@@ -180,17 +185,27 @@ export function getValidRange(
180 185
  */
181 186
 export function generateMarkedDates(
182 187
   isSelection: boolean,
183
-  theme: CustomThemeType,
188
+  theme: ReactNativePaper.Theme,
184 189
   range: Array<string>,
185 190
 ): MarkedDatesObjectType {
186
-  const markedDates = {};
191
+  const markedDates: {
192
+    [key: string]: {
193
+      startingDay: boolean;
194
+      endingDay: boolean;
195
+      color: string;
196
+    };
197
+  } = {};
187 198
   for (let i = 0; i < range.length; i += 1) {
188 199
     const isStart = i === 0;
189 200
     const isEnd = i === range.length - 1;
190 201
     let color;
191
-    if (isSelection && (isStart || isEnd)) color = theme.colors.primary;
192
-    else if (isSelection) color = theme.colors.danger;
193
-    else color = theme.colors.textDisabled;
202
+    if (isSelection && (isStart || isEnd)) {
203
+      color = theme.colors.primary;
204
+    } else if (isSelection) {
205
+      color = theme.colors.danger;
206
+    } else {
207
+      color = theme.colors.textDisabled;
208
+    }
194 209
     markedDates[range[i]] = {
195 210
       startingDay: isStart,
196 211
       endingDay: isEnd,

src/utils/Home.js → src/utils/Home.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import {stringToDate} from './Planning';
23 21
 import type {PlanningEventType} from './Planning';
24 22
 
@@ -29,13 +27,15 @@ import type {PlanningEventType} from './Planning';
29 27
  */
30 28
 export function getTodayEventTimeLimit(): Date {
31 29
   const now = new Date();
32
-  if (now.getDay() === 4)
30
+  if (now.getDay() === 4) {
33 31
     // Thursday
34 32
     now.setHours(11, 30, 0);
35
-  else if (now.getDay() === 6 || now.getDay() === 0)
33
+  } else if (now.getDay() === 6 || now.getDay() === 0) {
36 34
     // Weekend
37 35
     now.setHours(0, 0, 0);
38
-  else now.setHours(17, 30, 0);
36
+  } else {
37
+    now.setHours(17, 30, 0);
38
+  }
39 39
   return now;
40 40
 }
41 41
 
@@ -50,7 +50,7 @@ export function getEventsAfterLimit(
50 50
   events: Array<PlanningEventType>,
51 51
   limit: Date,
52 52
 ): Array<PlanningEventType> {
53
-  const validEvents = [];
53
+  const validEvents: Array<PlanningEventType> = [];
54 54
   events.forEach((event: PlanningEventType) => {
55 55
     const startDate = stringToDate(event.date_begin);
56 56
     if (startDate != null && startDate >= limit) {
@@ -68,11 +68,13 @@ export function getEventsAfterLimit(
68 68
 export function getFutureEvents(
69 69
   events: Array<PlanningEventType>,
70 70
 ): Array<PlanningEventType> {
71
-  const validEvents = [];
71
+  const validEvents: Array<PlanningEventType> = [];
72 72
   const now = new Date();
73 73
   events.forEach((event: PlanningEventType) => {
74 74
     const startDate = stringToDate(event.date_begin);
75
-    if (startDate != null && startDate > now) validEvents.push(event);
75
+    if (startDate != null && startDate > now) {
76
+      validEvents.push(event);
77
+    }
76 78
   });
77 79
   return validEvents;
78 80
 }
@@ -92,8 +94,13 @@ export function getDisplayEvent(
92 94
       events,
93 95
       getTodayEventTimeLimit(),
94 96
     );
95
-    if (eventsAfterLimit.length > 0) [displayEvent] = eventsAfterLimit;
96
-    else [displayEvent] = events;
97
-  } else if (events.length === 1) [displayEvent] = events;
97
+    if (eventsAfterLimit.length > 0) {
98
+      [displayEvent] = eventsAfterLimit;
99
+    } else {
100
+      [displayEvent] = events;
101
+    }
102
+  } else if (events.length === 1) {
103
+    [displayEvent] = events;
104
+  }
98 105
   return displayEvent;
99 106
 }

src/utils/Locales.js → src/utils/Locales.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import i18n from 'i18n-js';
23 21
 import * as RNLocalize from 'react-native-localize';
24 22
 
@@ -28,9 +26,7 @@ import fr from '../../locales/fr.json';
28 26
 const initLocales = () => {
29 27
   i18n.fallbacks = true;
30 28
   i18n.translations = {fr, en};
31
-  i18n.locale = RNLocalize.findBestAvailableLanguage([
32
-    'en',
33
-    'fr',
34
-  ]).languageTag;
35
-}
29
+  const bestLanguage = RNLocalize.findBestAvailableLanguage(['en', 'fr']);
30
+  i18n.locale = bestLanguage ? bestLanguage.languageTag : 'en';
31
+};
36 32
 export default initLocales;

src/utils/Notifications.js → src/utils/Notifications.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import {
23 21
   checkNotifications,
24 22
   requestNotifications,
@@ -41,12 +39,17 @@ const reminderIdFactor = 100;
41 39
 export async function askPermissions(): Promise<void> {
42 40
   return new Promise((resolve: () => void, reject: () => void) => {
43 41
     checkNotifications().then(({status}: {status: string}) => {
44
-      if (status === RESULTS.GRANTED) resolve();
45
-      else if (status === RESULTS.BLOCKED) reject();
46
-      else {
47
-        requestNotifications().then((result: {status: string}) => {
48
-          if (result.status === RESULTS.GRANTED) resolve();
49
-          else reject();
42
+      if (status === RESULTS.GRANTED) {
43
+        resolve();
44
+      } else if (status === RESULTS.BLOCKED) {
45
+        reject();
46
+      } else {
47
+        requestNotifications([]).then((result: {status: string}) => {
48
+          if (result.status === RESULTS.GRANTED) {
49
+            resolve();
50
+          } else {
51
+            reject();
52
+          }
50 53
         });
51 54
       }
52 55
     });

src/utils/Planning.js → src/utils/Planning.ts View File

@@ -17,18 +17,16 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 export type PlanningEventType = {
23
-  id: number,
24
-  title: string,
25
-  date_begin: string,
26
-  club: string,
27
-  category_id: number,
28
-  description: string,
29
-  place: string,
30
-  url: string,
31
-  logo: string | null,
21
+  id: number;
22
+  title: string;
23
+  date_begin: string;
24
+  club: string;
25
+  category_id: number;
26
+  description: string;
27
+  place: string;
28
+  url: string;
29
+  logo: string | null;
32 30
 };
33 31
 
34 32
 // Regex used to check date string validity
@@ -41,7 +39,7 @@ const dateRegExp = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/;
41 39
  * @param dateString The string to check
42 40
  * @return {boolean}
43 41
  */
44
-export function isEventDateStringFormatValid(dateString: ?string): boolean {
42
+export function isEventDateStringFormatValid(dateString?: string): boolean {
45 43
   return (
46 44
     dateString !== undefined &&
47 45
     dateString !== null &&
@@ -57,7 +55,7 @@ export function isEventDateStringFormatValid(dateString: ?string): boolean {
57 55
  * @return {Date|null} The date object or null if the given string is invalid
58 56
  */
59 57
 export function stringToDate(dateString: string): Date | null {
60
-  let date = new Date();
58
+  let date: Date | null = new Date();
61 59
   if (isEventDateStringFormatValid(dateString)) {
62 60
     const stringArray = dateString.split(' ');
63 61
     const dateArray = stringArray[0].split('-');
@@ -68,7 +66,9 @@ export function stringToDate(dateString: string): Date | null {
68 66
       parseInt(dateArray[2], 10),
69 67
     );
70 68
     date.setHours(parseInt(timeArray[0], 10), parseInt(timeArray[1], 10), 0, 0);
71
-  } else date = null;
69
+  } else {
70
+    date = null;
71
+  }
72 72
 
73 73
   return date;
74 74
 }
@@ -111,7 +111,9 @@ export function getCurrentDateString(): string {
111 111
 export function isEventBefore(event1Date: string, event2Date: string): boolean {
112 112
   const date1 = stringToDate(event1Date);
113 113
   const date2 = stringToDate(event2Date);
114
-  if (date1 !== null && date2 !== null) return date1 < date2;
114
+  if (date1 !== null && date2 !== null) {
115
+    return date1 < date2;
116
+  }
115 117
   return false;
116 118
 }
117 119
 
@@ -123,7 +125,9 @@ export function isEventBefore(event1Date: string, event2Date: string): boolean {
123 125
  * @return {string|null} Date in format YYYY:MM:DD or null if given string is invalid
124 126
  */
125 127
 export function getDateOnlyString(dateString: string): string | null {
126
-  if (isEventDateStringFormatValid(dateString)) return dateString.split(' ')[0];
128
+  if (isEventDateStringFormatValid(dateString)) {
129
+    return dateString.split(' ')[0];
130
+  }
127 131
   return null;
128 132
 }
129 133
 
@@ -135,7 +139,9 @@ export function getDateOnlyString(dateString: string): string | null {
135 139
  * @return {string|null} Time in format HH:MM or null if given string is invalid
136 140
  */
137 141
 export function getTimeOnlyString(dateString: string): string | null {
138
-  if (isEventDateStringFormatValid(dateString)) return dateString.split(' ')[1];
142
+  if (isEventDateStringFormatValid(dateString)) {
143
+    return dateString.split(' ')[1];
144
+  }
139 145
   return null;
140 146
 }
141 147
 
@@ -148,7 +154,7 @@ export function getTimeOnlyString(dateString: string): string | null {
148 154
  * @param description The text to check
149 155
  * @return {boolean}
150 156
  */
151
-export function isDescriptionEmpty(description: ?string): boolean {
157
+export function isDescriptionEmpty(description?: string): boolean {
152 158
   if (description !== undefined && description !== null) {
153 159
     return (
154 160
       description
@@ -177,10 +183,12 @@ export function generateEmptyCalendar(
177 183
 ): {[key: string]: Array<PlanningEventType>} {
178 184
   const end = new Date(Date.now());
179 185
   end.setMonth(end.getMonth() + numberOfMonths);
180
-  const daysOfYear = {};
186
+  const daysOfYear: {[key: string]: Array<PlanningEventType>} = {};
181 187
   for (let d = new Date(Date.now()); d <= end; d.setDate(d.getDate() + 1)) {
182 188
     const dateString = getDateOnlyString(dateToString(new Date(d), false));
183
-    if (dateString !== null) daysOfYear[dateString] = [];
189
+    if (dateString !== null) {
190
+      daysOfYear[dateString] = [];
191
+    }
184 192
   }
185 193
   return daysOfYear;
186 194
 }
@@ -197,8 +205,9 @@ export function pushEventInOrder(
197 205
   eventArray: Array<PlanningEventType>,
198 206
   event: PlanningEventType,
199 207
 ) {
200
-  if (eventArray.length === 0) eventArray.push(event);
201
-  else {
208
+  if (eventArray.length === 0) {
209
+    eventArray.push(event);
210
+  } else {
202 211
     for (let i = 0; i < eventArray.length; i += 1) {
203 212
       if (isEventBefore(event.date_begin, eventArray[i].date_begin)) {
204 213
         eventArray.splice(i, 0, event);
@@ -231,7 +240,9 @@ export function generateEventAgenda(
231 240
     const dateString = getDateOnlyString(eventList[i].date_begin);
232 241
     if (dateString != null) {
233 242
       const eventArray = agendaItems[dateString];
234
-      if (eventArray != null) pushEventInOrder(eventArray, eventList[i]);
243
+      if (eventArray != null) {
244
+        pushEventInOrder(eventArray, eventList[i]);
245
+      }
235 246
     }
236 247
   }
237 248
   return agendaItems;

src/utils/Proxiwash.js → src/utils/Proxiwash.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import type {ProxiwashMachineType} from '../screens/Proxiwash/ProxiwashScreen';
23 21
 
24 22
 /**
@@ -32,16 +30,21 @@ import type {ProxiwashMachineType} from '../screens/Proxiwash/ProxiwashScreen';
32 30
  */
33 31
 export function getMachineEndDate(machine: ProxiwashMachineType): Date | null {
34 32
   const array = machine.endTime.split(':');
35
-  let endDate = new Date(Date.now());
33
+  let endDate: Date | null = new Date(Date.now());
36 34
   endDate.setHours(parseInt(array[0], 10), parseInt(array[1], 10));
37 35
 
38 36
   const limit = new Date(Date.now());
39 37
   if (endDate < limit) {
40 38
     if (limit.getHours() > 12) {
41 39
       limit.setHours(limit.getHours() - 12);
42
-      if (endDate < limit) endDate.setDate(endDate.getDate() + 1);
43
-      else endDate = null;
44
-    } else endDate = null;
40
+      if (endDate < limit) {
41
+        endDate.setDate(endDate.getDate() + 1);
42
+      } else {
43
+        endDate = null;
44
+      }
45
+    } else {
46
+      endDate = null;
47
+    }
45 48
   }
46 49
 
47 50
   return endDate;
@@ -63,8 +66,9 @@ export function isMachineWatched(
63 66
     if (
64 67
       watchedMachine.number === machine.number &&
65 68
       watchedMachine.endTime === machine.endTime
66
-    )
69
+    ) {
67 70
       watched = true;
71
+    }
68 72
   });
69 73
   return watched;
70 74
 }
@@ -82,7 +86,9 @@ export function getMachineOfId(
82 86
 ): ProxiwashMachineType | null {
83 87
   let machineFound = null;
84 88
   allMachines.forEach((machine: ProxiwashMachineType) => {
85
-    if (machine.number === id) machineFound = machine;
89
+    if (machine.number === id) {
90
+      machineFound = machine;
91
+    }
86 92
   });
87 93
   return machineFound;
88 94
 }
@@ -100,7 +106,7 @@ export function getCleanedMachineWatched(
100 106
   machineWatchedList: Array<ProxiwashMachineType>,
101 107
   allMachines: Array<ProxiwashMachineType>,
102 108
 ): Array<ProxiwashMachineType> {
103
-  const newList = [];
109
+  const newList: Array<ProxiwashMachineType> = [];
104 110
   machineWatchedList.forEach((watchedMachine: ProxiwashMachineType) => {
105 111
     const machine = getMachineOfId(watchedMachine.number, allMachines);
106 112
     if (

src/utils/Search.js → src/utils/Search.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 /**
23 21
  * Sanitizes the given string to improve search performance.
24 22
  *
@@ -60,7 +58,9 @@ export function isItemInCategoryFilter(
60 58
 ): boolean {
61 59
   let itemFound = false;
62 60
   categories.forEach((cat: number | null) => {
63
-    if (cat != null && filter.indexOf(cat) !== -1) itemFound = true;
61
+    if (cat != null && filter.indexOf(cat) !== -1) {
62
+      itemFound = true;
63
+    }
64 64
   });
65 65
   return itemFound;
66 66
 }

src/utils/Utils.js → src/utils/Services.ts View File

@@ -17,10 +17,25 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22
-import {Platform, StatusBar} from 'react-native';
23
-import ThemeManager from '../managers/ThemeManager';
20
+/**
21
+ * Gets the given services list without items of the given ids
22
+ *
23
+ * @param idList The ids of items to remove
24
+ * @param sourceList The item list to use as source
25
+ * @returns {[]}
26
+ */
27
+export default function getStrippedServicesList<T extends {key: string}>(
28
+  idList: Array<string>,
29
+  sourceList: Array<T>,
30
+) {
31
+  const newArray: Array<T> = [];
32
+  sourceList.forEach((item: T) => {
33
+    if (!idList.includes(item.key)) {
34
+      newArray.push(item);
35
+    }
36
+  });
37
+  return newArray;
38
+}
24 39
 
25 40
 /**
26 41
  * Gets a sublist of the given list with items of the given ids only
@@ -31,11 +46,11 @@ import ThemeManager from '../managers/ThemeManager';
31 46
  * @param originalList The original list
32 47
  * @returns {[]}
33 48
  */
34
-export function getSublistWithIds<T>(
49
+export function getSublistWithIds<T extends {key: string}>(
35 50
   idList: Array<string>,
36
-  originalList: Array<{key: string, ...T}>,
37
-): Array<{key: string, ...T} | null> {
38
-  const subList = [];
51
+  originalList: Array<T>,
52
+) {
53
+  const subList: Array<T | null> = [];
39 54
   for (let i = 0; i < idList.length; i += 1) {
40 55
     subList.push(null);
41 56
   }
@@ -45,26 +60,10 @@ export function getSublistWithIds<T>(
45 60
     if (idList.includes(item.key)) {
46 61
       subList[idList.indexOf(item.key)] = item;
47 62
       itemsAdded += 1;
48
-      if (itemsAdded === idList.length) break;
63
+      if (itemsAdded === idList.length) {
64
+        break;
65
+      }
49 66
     }
50 67
   }
51 68
   return subList;
52 69
 }
53
-
54
-/**
55
- * Updates status bar content color if on iOS only,
56
- * as the android status bar is always set to black.
57
- */
58
-export function setupStatusBar() {
59
-  if (ThemeManager.getNightMode()) {
60
-    StatusBar.setBarStyle('light-content', true);
61
-  } else {
62
-    StatusBar.setBarStyle('dark-content', true);
63
-  }
64
-  if (Platform.OS === 'android') {
65
-    StatusBar.setBackgroundColor(
66
-      ThemeManager.getCurrentTheme().colors.surface,
67
-      true,
68
-    );
69
-  }
70
-}

src/utils/URLHandler.js → src/utils/URLHandler.ts View File

@@ -17,20 +17,18 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import {Linking} from 'react-native';
23 21
 
24 22
 export type ParsedUrlDataType = {
25
-  route: string,
26
-  data: {[key: string]: string},
23
+  route: string;
24
+  data: {[key: string]: string};
27 25
 };
28 26
 
29 27
 export type ParsedUrlCallbackType = (parsedData: ParsedUrlDataType) => void;
30 28
 
31 29
 type RawParsedUrlDataType = {
32
-  path: string,
33
-  queryParams: {[key: string]: string},
30
+  path: string;
31
+  queryParams: {[key: string]: string};
34 32
 };
35 33
 
36 34
 /**
@@ -69,7 +67,7 @@ export default class URLHandler {
69 67
     let parsedData: RawParsedUrlDataType | null = null;
70 68
     const urlNoScheme = url.replace(URLHandler.SCHEME, '');
71 69
     if (urlNoScheme != null) {
72
-      const params = {};
70
+      const params: {[key: string]: string} = {};
73 71
       const [path, fullParamsString] = urlNoScheme.split('?');
74 72
       if (fullParamsString != null) {
75 73
         const paramsStringArray = fullParamsString.split('&');
@@ -80,7 +78,9 @@ export default class URLHandler {
80 78
           }
81 79
         });
82 80
       }
83
-      if (path != null) parsedData = {path, queryParams: params};
81
+      if (path != null) {
82
+        parsedData = {path, queryParams: params};
83
+      }
84 84
     }
85 85
     return parsedData;
86 86
   }
@@ -99,10 +99,11 @@ export default class URLHandler {
99 99
     if (rawParsedUrlData != null) {
100 100
       const {path} = rawParsedUrlData;
101 101
       const {queryParams} = rawParsedUrlData;
102
-      if (URLHandler.isClubInformationLink(path))
102
+      if (URLHandler.isClubInformationLink(path)) {
103 103
         parsedData = URLHandler.generateClubInformationData(queryParams);
104
-      else if (URLHandler.isPlanningInformationLink(path))
104
+      } else if (URLHandler.isPlanningInformationLink(path)) {
105 105
         parsedData = URLHandler.generatePlanningInformationData(queryParams);
106
+      }
106 107
     }
107 108
 
108 109
     return parsedData;
@@ -145,15 +146,16 @@ export default class URLHandler {
145 146
    * @returns {null|{route: string, data: {clubId: number}}}
146 147
    */
147 148
   static generateClubInformationData(params: {
148
-    [key: string]: string,
149
+    [key: string]: string;
149 150
   }): ParsedUrlDataType | null {
150 151
     if (params.id != null) {
151 152
       const id = parseInt(params.id, 10);
152
-      if (!Number.isNaN(id))
153
+      if (!Number.isNaN(id)) {
153 154
         return {
154 155
           route: URLHandler.CLUB_INFO_ROUTE,
155 156
           data: {clubId: id.toString()},
156 157
         };
158
+      }
157 159
     }
158 160
     return null;
159 161
   }
@@ -165,7 +167,7 @@ export default class URLHandler {
165 167
    * @returns {null|{route: string, data: {clubId: number}}}
166 168
    */
167 169
   static generatePlanningInformationData(params: {
168
-    [key: string]: string,
170
+    [key: string]: string;
169 171
   }): ParsedUrlDataType | null {
170 172
     if (params.id != null) {
171 173
       const id = parseInt(params.id, 10);
@@ -201,7 +203,9 @@ export default class URLHandler {
201 203
   onUrl = ({url}: {url: string}) => {
202 204
     if (url != null) {
203 205
       const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
204
-      if (data != null) this.onDetectURL(data);
206
+      if (data != null) {
207
+        this.onDetectURL(data);
208
+      }
205 209
     }
206 210
   };
207 211
 
@@ -210,10 +214,12 @@ export default class URLHandler {
210 214
    *
211 215
    * @param url The url detected
212 216
    */
213
-  onInitialUrl = (url: ?string) => {
217
+  onInitialUrl = (url: string | null) => {
214 218
     if (url != null) {
215 219
       const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
216
-      if (data != null) this.onInitialURLParsed(data);
220
+      if (data != null) {
221
+        this.onInitialURLParsed(data);
222
+      }
217 223
     }
218 224
   };
219 225
 }

src/utils/Services.js → src/utils/Utils.ts View File

@@ -17,22 +17,23 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
20
+import {Platform, StatusBar} from 'react-native';
21
+import ThemeManager from '../managers/ThemeManager';
21 22
 
22 23
 /**
23
- * Gets the given services list without items of the given ids
24
- *
25
- * @param idList The ids of items to remove
26
- * @param sourceList The item list to use as source
27
- * @returns {[]}
24
+ * Updates status bar content color if on iOS only,
25
+ * as the android status bar is always set to black.
28 26
  */
29
-export default function getStrippedServicesList<T>(
30
-  idList: Array<string>,
31
-  sourceList: Array<{key: string, ...T}>,
32
-): Array<{key: string, ...T}> {
33
-  const newArray = [];
34
-  sourceList.forEach((item: {key: string, ...T}) => {
35
-    if (!idList.includes(item.key)) newArray.push(item);
36
-  });
37
-  return newArray;
27
+export function setupStatusBar() {
28
+  if (ThemeManager.getNightMode()) {
29
+    StatusBar.setBarStyle('light-content', true);
30
+  } else {
31
+    StatusBar.setBarStyle('dark-content', true);
32
+  }
33
+  if (Platform.OS === 'android') {
34
+    StatusBar.setBackgroundColor(
35
+      ThemeManager.getCurrentTheme().colors.surface,
36
+      true,
37
+    );
38
+  }
38 39
 }

src/utils/WebData.js → src/utils/WebData.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 export const ERROR_TYPE = {
23 21
   SUCCESS: 0,
24 22
   BAD_CREDENTIALS: 1,
@@ -34,15 +32,14 @@ export const ERROR_TYPE = {
34 32
 };
35 33
 
36 34
 export type ApiDataLoginType = {
37
-  token: string,
35
+  token: string;
38 36
 };
39 37
 
40
-// eslint-disable-next-line flowtype/no-weak-types
41 38
 export type ApiGenericDataType = {[key: string]: any};
42 39
 
43
-type ApiResponseType = {
44
-  error: number,
45
-  data: ApiGenericDataType,
40
+type ApiResponseType<T> = {
41
+  error: number;
42
+  data: T;
46 43
 };
47 44
 
48 45
 const API_ENDPOINT = 'https://www.amicale-insat.fr/api/';
@@ -55,11 +52,10 @@ const API_ENDPOINT = 'https://www.amicale-insat.fr/api/';
55 52
  * @param response
56 53
  * @returns {boolean}
57 54
  */
58
-export function isApiResponseValid(response: ApiResponseType): boolean {
55
+export function isApiResponseValid<T>(response: ApiResponseType<T>): boolean {
59 56
   return (
60 57
     response != null &&
61 58
     response.error != null &&
62
-    typeof response.error === 'number' &&
63 59
     response.data != null &&
64 60
     typeof response.data === 'object'
65 61
   );
@@ -76,18 +72,17 @@ export function isApiResponseValid(response: ApiResponseType): boolean {
76 72
  * @param params The params to use for this request
77 73
  * @returns {Promise<ApiGenericDataType>}
78 74
  */
79
-export async function apiRequest(
75
+export async function apiRequest<T>(
80 76
   path: string,
81 77
   method: string,
82
-  params?: {...},
83
-): Promise<ApiGenericDataType> {
78
+  params?: object,
79
+): Promise<T> {
84 80
   return new Promise(
85
-    (
86
-      resolve: (data: ApiGenericDataType) => void,
87
-      reject: (error: number) => void,
88
-    ) => {
81
+    (resolve: (data: T) => void, reject: (error: number) => void) => {
89 82
       let requestParams = {};
90
-      if (params != null) requestParams = {...params};
83
+      if (params != null) {
84
+        requestParams = {...params};
85
+      }
91 86
       fetch(API_ENDPOINT + path, {
92 87
         method,
93 88
         headers: new Headers({
@@ -96,14 +91,20 @@ export async function apiRequest(
96 91
         }),
97 92
         body: JSON.stringify(requestParams),
98 93
       })
99
-        .then(async (response: Response): Promise<ApiResponseType> =>
100
-          response.json(),
94
+        .then(
95
+          async (response: Response): Promise<ApiResponseType<T>> =>
96
+            response.json(),
101 97
         )
102
-        .then((response: ApiResponseType) => {
98
+        .then((response: ApiResponseType<T>) => {
103 99
           if (isApiResponseValid(response)) {
104
-            if (response.error === ERROR_TYPE.SUCCESS) resolve(response.data);
105
-            else reject(response.error);
106
-          } else reject(ERROR_TYPE.SERVER_ERROR);
100
+            if (response.error === ERROR_TYPE.SUCCESS) {
101
+              resolve(response.data);
102
+            } else {
103
+              reject(response.error);
104
+            }
105
+          } else {
106
+            reject(ERROR_TYPE.SERVER_ERROR);
107
+          }
107 108
         })
108 109
         .catch((): void => reject(ERROR_TYPE.CONNECTION_ERROR));
109 110
     },
@@ -121,14 +122,10 @@ export async function apiRequest(
121 122
  * @param url The urls to fetch data from
122 123
  * @return Promise<any>
123 124
  */
124
-// eslint-disable-next-line flowtype/no-weak-types
125 125
 export async function readData(url: string): Promise<any> {
126
-  // eslint-disable-next-line flowtype/no-weak-types
127 126
   return new Promise((resolve: (response: any) => void, reject: () => void) => {
128 127
     fetch(url)
129
-      // eslint-disable-next-line flowtype/no-weak-types
130 128
       .then(async (response: Response): Promise<any> => response.json())
131
-      // eslint-disable-next-line flowtype/no-weak-types
132 129
       .then((data: any): void => resolve(data))
133 130
       .catch((): void => reject());
134 131
   });

src/utils/withCollapsible.js → src/utils/withCollapsible.tsx View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import * as React from 'react';
23 21
 import {useCollapsibleStack} from 'react-navigation-collapsible';
24 22
 
@@ -35,18 +33,12 @@ import {useCollapsibleStack} from 'react-navigation-collapsible';
35 33
  * @param Component The component to use Collapsible with
36 34
  * @returns {React.ComponentType<any>}
37 35
  */
38
-export default function withCollapsible(
39
-  // eslint-disable-next-line flowtype/no-weak-types
40
-  Component: React.ComponentType<any>,
41
-  // eslint-disable-next-line flowtype/no-weak-types
42
-): React$AbstractComponent<any, any> {
43
-  // eslint-disable-next-line flowtype/no-weak-types
44
-  return React.forwardRef((props: any, ref: any): React.Node => {
36
+export default function withCollapsible(Component: React.ComponentType<any>) {
37
+  return React.forwardRef((props: any, ref: any) => {
45 38
     return (
46 39
       <Component
47 40
         collapsibleStack={useCollapsibleStack()}
48 41
         ref={ref}
49
-        // eslint-disable-next-line react/jsx-props-no-spreading
50 42
         {...props}
51 43
       />
52 44
     );

Loading…
Cancel
Save