Browse Source

Improved doc and typing and removed unused file

Arnaud Vergnet 3 years ago
parent
commit
b66e50eaf8

+ 7
- 7
src/screens/About/AboutDependenciesScreen.js View File

@@ -4,6 +4,7 @@ import * as React from 'react';
4 4
 import {FlatList} from "react-native";
5 5
 import packageJson from '../../../package';
6 6
 import {List} from 'react-native-paper';
7
+import {StackNavigationProp} from "@react-navigation/stack";
7 8
 
8 9
 type listItem = {
9 10
     name: string,
@@ -16,7 +17,7 @@ type listItem = {
16 17
  * @param object The raw json
17 18
  * @return {Array<listItem>}
18 19
  */
19
-function generateListFromObject(object: { [string]: string }): Array<listItem> {
20
+function generateListFromObject(object: { [key: string]: string }): Array<listItem> {
20 21
     let list = [];
21 22
     let keys = Object.keys(object);
22 23
     let values = Object.values(object);
@@ -28,8 +29,7 @@ function generateListFromObject(object: { [string]: string }): Array<listItem> {
28 29
 }
29 30
 
30 31
 type Props = {
31
-    navigation: Object,
32
-    route: Object
32
+    navigation: StackNavigationProp,
33 33
 }
34 34
 
35 35
 const LIST_ITEM_HEIGHT = 64;
@@ -39,23 +39,23 @@ const LIST_ITEM_HEIGHT = 64;
39 39
  */
40 40
 export default class AboutDependenciesScreen extends React.Component<Props> {
41 41
 
42
-    data: Array<Object>;
42
+    data: Array<listItem>;
43 43
 
44 44
     constructor() {
45 45
         super();
46 46
         this.data = generateListFromObject(packageJson.dependencies);
47 47
     }
48 48
 
49
-    keyExtractor = (item: Object) => item.name;
49
+    keyExtractor = (item: listItem) => item.name;
50 50
 
51
-    renderItem = ({item}: Object) =>
51
+    renderItem = ({item}: { item: listItem }) =>
52 52
         <List.Item
53 53
             title={item.name}
54 54
             description={item.version.replace('^', '').replace('~', '')}
55 55
             style={{height: LIST_ITEM_HEIGHT}}
56 56
         />;
57 57
 
58
-    itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
58
+    itemLayout = (data: any, index: number) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
59 59
 
60 60
     render() {
61 61
         return (

+ 21
- 20
src/screens/About/AboutScreen.js View File

@@ -5,6 +5,14 @@ import {FlatList, Linking, Platform, View} from 'react-native';
5 5
 import i18n from "i18n-js";
6 6
 import {Avatar, Card, List, Title, withTheme} from 'react-native-paper';
7 7
 import packageJson from "../../../package.json";
8
+import {StackNavigationProp} from "@react-navigation/stack";
9
+
10
+type ListItem = {
11
+    onPressCallback: () => void,
12
+    icon: string,
13
+    text: string,
14
+    showChevron: boolean
15
+};
8 16
 
9 17
 const links = {
10 18
     appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
@@ -29,7 +37,7 @@ const links = {
29 37
 };
30 38
 
31 39
 type Props = {
32
-    navigation: Object,
40
+    navigation: StackNavigationProp,
33 41
 };
34 42
 
35 43
 /**
@@ -48,7 +56,7 @@ class AboutScreen extends React.Component<Props> {
48 56
     /**
49 57
      * Data to be displayed in the app card
50 58
      */
51
-    appData: Array<Object> = [
59
+    appData = [
52 60
         {
53 61
             onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
54 62
             icon: Platform.OS === "ios" ? 'apple' : 'google-play',
@@ -83,7 +91,7 @@ class AboutScreen extends React.Component<Props> {
83 91
     /**
84 92
      * Data to be displayed in the author card
85 93
      */
86
-    authorData: Array<Object> = [
94
+    authorData = [
87 95
         {
88 96
             onPressCallback: () => openWebLink(links.meme),
89 97
             icon: 'account-circle',
@@ -106,7 +114,7 @@ class AboutScreen extends React.Component<Props> {
106 114
     /**
107 115
      * Data to be displayed in the additional developer card
108 116
      */
109
-    additionalDevData: Array<Object> = [
117
+    additionalDevData = [
110 118
         {
111 119
             onPressCallback: () => console.log('Meme this'),
112 120
             icon: 'account',
@@ -129,7 +137,7 @@ class AboutScreen extends React.Component<Props> {
129 137
     /**
130 138
      * Data to be displayed in the technologies card
131 139
      */
132
-    technoData: Array<Object> = [
140
+    technoData = [
133 141
         {
134 142
             onPressCallback: () => openWebLink(links.react),
135 143
             icon: 'react',
@@ -146,7 +154,7 @@ class AboutScreen extends React.Component<Props> {
146 154
     /**
147 155
      * Order of information cards
148 156
      */
149
-    dataOrder: Array<Object> = [
157
+    dataOrder = [
150 158
         {
151 159
             id: 'app',
152 160
         },
@@ -158,16 +166,9 @@ class AboutScreen extends React.Component<Props> {
158 166
         },
159 167
     ];
160 168
 
161
-
162
-    colors: Object;
163
-
164
-    constructor(props) {
165
-        super(props);
166
-        this.colors = props.theme.colors;
167
-    }
168
-
169 169
     /**
170 170
      * Gets the app icon
171
+     *
171 172
      * @param props
172 173
      * @return {*}
173 174
      */
@@ -187,7 +188,7 @@ class AboutScreen extends React.Component<Props> {
187 188
      * @param item The item to extract the key from
188 189
      * @return {string} The extracted key
189 190
      */
190
-    keyExtractor(item: Object): string {
191
+    keyExtractor(item: ListItem): string {
191 192
         return item.icon;
192 193
     }
193 194
 
@@ -271,7 +272,7 @@ class AboutScreen extends React.Component<Props> {
271 272
      * @param props
272 273
      * @return {*}
273 274
      */
274
-    getChevronIcon(props: Object) {
275
+    getChevronIcon(props) {
275 276
         return (
276 277
             <List.Icon {...props} icon={'chevron-right'}/>
277 278
         );
@@ -284,18 +285,18 @@ class AboutScreen extends React.Component<Props> {
284 285
      * @param props
285 286
      * @return {*}
286 287
      */
287
-    getItemIcon(item: Object, props: Object) {
288
+    getItemIcon(item: ListItem, props) {
288 289
         return (
289 290
             <List.Icon {...props} icon={item.icon}/>
290 291
         );
291 292
     }
292 293
 
293 294
     /**
294
-     * Get a clickable card item to be rendered inside a card.
295
+     * Gets a clickable card item to be rendered inside a card.
295 296
      *
296 297
      * @returns {*}
297 298
      */
298
-    getCardItem = ({item}: Object) => {
299
+    getCardItem = ({item}: { item: ListItem }) => {
299 300
         const getItemIcon = this.getItemIcon.bind(this, item);
300 301
         if (item.showChevron) {
301 302
             return (
@@ -323,7 +324,7 @@ class AboutScreen extends React.Component<Props> {
323 324
      * @param item The item to show
324 325
      * @return {*}
325 326
      */
326
-    getMainCard = ({item}: Object) => {
327
+    getMainCard = ({item}: { item: { id: string } }) => {
327 328
         switch (item.id) {
328 329
             case 'app':
329 330
                 return this.getAppCard();

+ 36
- 19
src/screens/About/DebugScreen.js View File

@@ -5,14 +5,24 @@ import {FlatList, View} from "react-native";
5 5
 import AsyncStorageManager from "../../managers/AsyncStorageManager";
6 6
 import CustomModal from "../../components/Overrides/CustomModal";
7 7
 import {Button, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper';
8
+import {StackNavigationProp} from "@react-navigation/stack";
9
+import {Modalize} from "react-native-modalize";
10
+import type {CustomTheme} from "../../managers/ThemeManager";
11
+
12
+type PreferenceItem = {
13
+    key: string,
14
+    default: string,
15
+    current: string,
16
+}
8 17
 
9 18
 type Props = {
10
-    navigation: Object,
19
+    navigation: StackNavigationProp,
20
+    theme: CustomTheme
11 21
 };
12 22
 
13 23
 type State = {
14
-    modalCurrentDisplayItem: Object,
15
-    currentPreferences: Array<Object>,
24
+    modalCurrentDisplayItem: PreferenceItem,
25
+    currentPreferences: Array<PreferenceItem>,
16 26
 }
17 27
 
18 28
 /**
@@ -21,20 +31,20 @@ type State = {
21 31
  */
22 32
 class DebugScreen extends React.Component<Props, State> {
23 33
 
24
-    modalRef: Object;
25
-    modalInputValue = '';
26
-
27
-    onModalRef: Function;
28
-
29
-    colors: Object;
34
+    modalRef: Modalize;
35
+    modalInputValue: string;
30 36
 
37
+    /**
38
+     * Copies user preferences to state for easier manipulation
39
+     *
40
+     * @param props
41
+     */
31 42
     constructor(props) {
32 43
         super(props);
33
-        this.onModalRef = this.onModalRef.bind(this);
34
-        this.colors = props.theme.colors;
44
+        this.modalInputValue = "";
35 45
         let copy = {...AsyncStorageManager.getInstance().preferences};
36
-        let currentPreferences = [];
37
-        Object.values(copy).map((object) => {
46
+        let currentPreferences : Array<PreferenceItem> = [];
47
+        Object.values(copy).map((object: any) => {
38 48
             currentPreferences.push(object);
39 49
         });
40 50
         this.state = {
@@ -44,10 +54,11 @@ class DebugScreen extends React.Component<Props, State> {
44 54
     }
45 55
 
46 56
     /**
47
-     * Show the edit modal
57
+     * Shows the edit modal
58
+     *
48 59
      * @param item
49 60
      */
50
-    showEditModal(item: Object) {
61
+    showEditModal(item: PreferenceItem) {
51 62
         this.setState({
52 63
             modalCurrentDisplayItem: item
53 64
         });
@@ -81,14 +92,14 @@ class DebugScreen extends React.Component<Props, State> {
81 92
                     <Button
82 93
                         mode="contained"
83 94
                         dark={true}
84
-                        color={this.colors.success}
95
+                        color={this.props.theme.colors.success}
85 96
                         onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
86 97
                         Save new value
87 98
                     </Button>
88 99
                     <Button
89 100
                         mode="contained"
90 101
                         dark={true}
91
-                        color={this.colors.danger}
102
+                        color={this.props.theme.colors.danger}
92 103
                         onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.state.modalCurrentDisplayItem.default)}>
93 104
                         Reset to default
94 105
                     </Button>
@@ -98,6 +109,12 @@ class DebugScreen extends React.Component<Props, State> {
98 109
         );
99 110
     }
100 111
 
112
+    /**
113
+     * Finds the index of the given key in the preferences array
114
+     *
115
+     * @param key THe key to find the index of
116
+     * @returns {number}
117
+     */
101 118
     findIndexOfKey(key: string) {
102 119
         let index = -1;
103 120
         for (let i = 0; i < this.state.currentPreferences.length; i++) {
@@ -130,11 +147,11 @@ class DebugScreen extends React.Component<Props, State> {
130 147
      *
131 148
      * @param ref
132 149
      */
133
-    onModalRef(ref: Object) {
150
+    onModalRef = (ref: Modalize) => {
134 151
         this.modalRef = ref;
135 152
     }
136 153
 
137
-    renderItem = ({item}: Object) => {
154
+    renderItem = ({item}: {item: PreferenceItem}) => {
138 155
         return (
139 156
             <List.Item
140 157
                 title={item.key}

+ 10
- 13
src/screens/Amicale/AmicaleContactScreen.js View File

@@ -12,14 +12,18 @@ type Props = {
12 12
     collapsibleStack: Collapsible
13 13
 };
14 14
 
15
-type State = {};
15
+type DatasetItem = {
16
+    name: string,
17
+    email: string,
18
+    icon: string,
19
+}
16 20
 
17 21
 /**
18 22
  * Class defining a planning event information page.
19 23
  */
20
-class AmicaleContactScreen extends React.Component<Props, State> {
21
-
24
+class AmicaleContactScreen extends React.Component<Props> {
22 25
 
26
+    // Dataset containing information about contacts
23 27
     CONTACT_DATASET = [
24 28
         {
25 29
             name: i18n.t("amicaleAbout.roles.interSchools"),
@@ -68,18 +72,11 @@ class AmicaleContactScreen extends React.Component<Props, State> {
68 72
         },
69 73
     ];
70 74
 
71
-    colors: Object;
72
-
73
-    constructor(props) {
74
-        super(props);
75
-        this.colors = props.theme.colors;
76
-    }
77
-
78
-    keyExtractor = (item: Object) => item.email;
75
+    keyExtractor = (item: DatasetItem) => item.email;
79 76
 
80
-    getChevronIcon = (props: Object) => <List.Icon {...props} icon={'chevron-right'}/>;
77
+    getChevronIcon = (props) => <List.Icon {...props} icon={'chevron-right'}/>;
81 78
 
82
-    renderItem = ({item}: Object) => {
79
+    renderItem = ({item}: { item: DatasetItem }) => {
83 80
         const onPress = () => Linking.openURL('mailto:' + item.email);
84 81
         return <List.Item
85 82
             title={item.name}

+ 0
- 85
src/screens/Amicale/AmicaleHomeScreen.js View File

@@ -1,85 +0,0 @@
1
-// @flow
2
-
3
-import * as React from 'react';
4
-import {ScrollView, StyleSheet} from "react-native";
5
-import {Button, withTheme} from 'react-native-paper';
6
-
7
-type Props = {
8
-    navigation: Object,
9
-    route: Object,
10
-}
11
-
12
-type State = {}
13
-
14
-class AmicaleHomeScreen extends React.Component<Props, State> {
15
-
16
-    state = {};
17
-
18
-    colors: Object;
19
-
20
-    constructor(props) {
21
-        super(props);
22
-
23
-        this.colors = props.theme.colors;
24
-    }
25
-
26
-    render() {
27
-        const nav = this.props.navigation;
28
-        return (
29
-            <ScrollView>
30
-                <Button
31
-                    icon={"login"}
32
-                    onPress={() => nav.navigate("login")}
33
-                >
34
-                    LOGIN
35
-                </Button>
36
-                <Button
37
-                    icon={"information"}
38
-                    onPress={() => nav.navigate("amicale-contact")}
39
-                >
40
-                    INFO
41
-                </Button>
42
-                <Button
43
-                    icon={"information"}
44
-                    onPress={() => nav.navigate("club-list")}
45
-                >
46
-                    CLUBS
47
-                </Button>
48
-                <Button
49
-                    icon={"information"}
50
-                    onPress={() => nav.navigate("profile")}
51
-                >
52
-                    PROFILE
53
-                </Button>
54
-                <Button
55
-                    icon={"information"}
56
-                    onPress={() => nav.navigate("vote")}
57
-                >
58
-                    VOTE
59
-                </Button>
60
-            </ScrollView>
61
-        );
62
-    }
63
-}
64
-
65
-const styles = StyleSheet.create({
66
-    container: {
67
-        flex: 1,
68
-        flexDirection: 'column',
69
-        justifyContent: 'center',
70
-    },
71
-    card: {
72
-        margin: 10,
73
-    },
74
-    header: {
75
-        fontSize: 36,
76
-        marginBottom: 48
77
-    },
78
-    textInput: {},
79
-    btnContainer: {
80
-        marginTop: 5,
81
-        marginBottom: 10,
82
-    }
83
-});
84
-
85
-export default withTheme(AmicaleHomeScreen);

+ 2
- 16
src/screens/Amicale/Clubs/ClubAboutScreen.js View File

@@ -6,25 +6,11 @@ import {Card, List, Text, withTheme} from 'react-native-paper';
6 6
 import i18n from 'i18n-js';
7 7
 import Autolink from "react-native-autolink";
8 8
 
9
-type Props = {
10
-};
11
-
12
-type State = {
13
-};
9
+type Props = {};
14 10
 
15 11
 const CONTACT_LINK = 'clubs@amicale-insat.fr';
16 12
 
17
-/**
18
- * Class defining a planning event information page.
19
- */
20
-class ClubAboutScreen extends React.Component<Props, State> {
21
-
22
-    colors: Object;
23
-
24
-    constructor(props) {
25
-        super(props);
26
-        this.colors = props.theme.colors;
27
-    }
13
+class ClubAboutScreen extends React.Component<Props> {
28 14
 
29 15
     render() {
30 16
         return (

+ 44
- 11
src/screens/Amicale/Clubs/ClubDisplayScreen.js View File

@@ -65,6 +65,12 @@ class ClubDisplayScreen extends React.Component<Props, State> {
65 65
         }
66 66
     }
67 67
 
68
+    /**
69
+     * Gets the name of the category with the given ID
70
+     *
71
+     * @param id The category's ID
72
+     * @returns {string|*}
73
+     */
68 74
     getCategoryName(id: number) {
69 75
         if (this.categories !== null) {
70 76
             for (let i = 0; i < this.categories.length; i++) {
@@ -75,6 +81,12 @@ class ClubDisplayScreen extends React.Component<Props, State> {
75 81
         return "";
76 82
     }
77 83
 
84
+    /**
85
+     * Gets the view for rendering categories
86
+     *
87
+     * @param categories The categories to display (max 2)
88
+     * @returns {null|*}
89
+     */
78 90
     getCategoriesRender(categories: [number, number]) {
79 91
         if (this.categories === null)
80 92
             return null;
@@ -95,12 +107,19 @@ class ClubDisplayScreen extends React.Component<Props, State> {
95 107
         return <View style={{flexDirection: 'row', marginTop: 5}}>{final}</View>;
96 108
     }
97 109
 
98
-    getManagersRender(resp: Array<string>, email: string | null) {
99
-        let final = [];
100
-        for (let i = 0; i < resp.length; i++) {
101
-            final.push(<Paragraph key={i.toString()}>{resp[i]}</Paragraph>)
110
+    /**
111
+     * Gets the view for rendering club managers if any
112
+     *
113
+     * @param managers The list of manager names
114
+     * @param email The club contact email
115
+     * @returns {*}
116
+     */
117
+    getManagersRender(managers: Array<string>, email: string | null) {
118
+        let managersListView = [];
119
+        for (let i = 0; i < managers.length; i++) {
120
+            managersListView.push(<Paragraph key={i.toString()}>{managers[i]}</Paragraph>)
102 121
         }
103
-        const hasManagers = resp.length > 0;
122
+        const hasManagers = managers.length > 0;
104 123
         return (
105 124
             <Card style={{marginTop: 10, marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20}}>
106 125
                 <Card.Title
@@ -113,13 +132,20 @@ class ClubDisplayScreen extends React.Component<Props, State> {
113 132
                         icon="account-tie"/>}
114 133
                 />
115 134
                 <Card.Content>
116
-                    {final}
135
+                    {managersListView}
117 136
                     {this.getEmailButton(email, hasManagers)}
118 137
                 </Card.Content>
119 138
             </Card>
120 139
         );
121 140
     }
122 141
 
142
+    /**
143
+     * Gets the email button to contact the club, or the amicale if the club does not have any managers
144
+     *
145
+     * @param email The club contact email
146
+     * @param hasManagers True if the club has managers
147
+     * @returns {*}
148
+     */
123 149
     getEmailButton(email: string | null, hasManagers: boolean) {
124 150
         const destinationEmail = email != null && hasManagers
125 151
             ? email
@@ -141,13 +167,21 @@ class ClubDisplayScreen extends React.Component<Props, State> {
141 167
         );
142 168
     }
143 169
 
144
-    updateHeaderTitle(data: Object) {
170
+    /**
171
+     * Updates the header title to match the given club
172
+     *
173
+     * @param data The club data
174
+     */
175
+    updateHeaderTitle(data: club) {
145 176
         this.props.navigation.setOptions({title: data.name})
146 177
     }
147 178
 
148
-    getScreen = (response: Array<Object>) => {
149
-        let data: club = response[0];
150
-        this.updateHeaderTitle(data);
179
+    getScreen = (response: Array<{ [key: string]: any } | null>) => {
180
+        let data: club | null = null;
181
+        if (response[0] != null) {
182
+            data = response[0];
183
+            this.updateHeaderTitle(data);
184
+        }
151 185
         if (data != null) {
152 186
             return (
153 187
                 <ScrollView style={{paddingLeft: 5, paddingRight: 5}}>
@@ -184,7 +218,6 @@ class ClubDisplayScreen extends React.Component<Props, State> {
184 218
             );
185 219
         } else
186 220
             return null;
187
-
188 221
     };
189 222
 
190 223
     render() {

+ 26
- 0
src/screens/Amicale/Clubs/ClubListScreen.js View File

@@ -131,6 +131,15 @@ class ClubListScreen extends React.Component<Props, State> {
131 131
 
132 132
     onChipSelect = (id: number) => this.updateFilteredData(null, id);
133 133
 
134
+    /**
135
+     * Updates the search string and category filter, saving them to the State.
136
+     *
137
+     * If the given category is already in the filter, it removes it.
138
+     * Otherwise it adds it to the filter.
139
+     *
140
+     * @param filterStr The new filter string to use
141
+     * @param categoryId The category to add/remove from the filter
142
+     */
134 143
     updateFilteredData(filterStr: string | null, categoryId: number | null) {
135 144
         let newCategoriesState = [...this.state.currentlySelectedCategories];
136 145
         let newStrState = this.state.currentSearchString;
@@ -150,6 +159,11 @@ class ClubListScreen extends React.Component<Props, State> {
150 159
             })
151 160
     }
152 161
 
162
+    /**
163
+     * Gets the list header, with controls to change the categories filter
164
+     *
165
+     * @returns {*}
166
+     */
153 167
     getListHeader() {
154 168
         return <ClubListHeader
155 169
             categories={this.categories}
@@ -158,6 +172,12 @@ class ClubListScreen extends React.Component<Props, State> {
158 172
         />;
159 173
     }
160 174
 
175
+    /**
176
+     * Gets the category object of the given ID
177
+     *
178
+     * @param id The ID of the category to find
179
+     * @returns {*}
180
+     */
161 181
     getCategoryOfId = (id: number) => {
162 182
         for (let i = 0; i < this.categories.length; i++) {
163 183
             if (id === this.categories[i].id)
@@ -165,6 +185,12 @@ class ClubListScreen extends React.Component<Props, State> {
165 185
         }
166 186
     };
167 187
 
188
+    /**
189
+     * Checks if the given item should be rendered according to current name and category filters
190
+     *
191
+     * @param item The club to check
192
+     * @returns {boolean}
193
+     */
168 194
     shouldRenderItem(item: club) {
169 195
         let shouldRender = this.state.currentlySelectedCategories.length === 0
170 196
             || isItemInCategoryFilter(this.state.currentlySelectedCategories, item.category);

+ 93
- 10
src/screens/Amicale/LoginScreen.js View File

@@ -11,10 +11,11 @@ import {Collapsible} from "react-navigation-collapsible";
11 11
 import CustomTabBar from "../../components/Tabbar/CustomTabBar";
12 12
 import type {CustomTheme} from "../../managers/ThemeManager";
13 13
 import AsyncStorageManager from "../../managers/AsyncStorageManager";
14
+import {StackNavigationProp} from "@react-navigation/stack";
14 15
 
15 16
 type Props = {
16
-    navigation: Object,
17
-    route: Object,
17
+    navigation: StackNavigationProp,
18
+    route: { params: { nextScreen: string } },
18 19
     collapsibleStack: Collapsible,
19 20
     theme: CustomTheme
20 21
 }
@@ -47,9 +48,9 @@ class LoginScreen extends React.Component<Props, State> {
47 48
         dialogError: 0,
48 49
     };
49 50
 
50
-    onEmailChange: Function;
51
-    onPasswordChange: Function;
52
-    passwordInputRef: Object;
51
+    onEmailChange: (value: string) => null;
52
+    onPasswordChange: (value: string) => null;
53
+    passwordInputRef: { current: null | TextInput };
53 54
 
54 55
     nextScreen: string | null;
55 56
 
@@ -64,7 +65,10 @@ class LoginScreen extends React.Component<Props, State> {
64 65
         this.handleNavigationParams();
65 66
     };
66 67
 
67
-    handleNavigationParams () {
68
+    /**
69
+     * Saves the screen to navigate to after a successful login if one was provided in navigation parameters
70
+     */
71
+    handleNavigationParams() {
68 72
         if (this.props.route.params != null) {
69 73
             if (this.props.route.params.nextScreen != null)
70 74
                 this.nextScreen = this.props.route.params.nextScreen;
@@ -73,6 +77,11 @@ class LoginScreen extends React.Component<Props, State> {
73 77
         }
74 78
     }
75 79
 
80
+    /**
81
+     * Shows an error dialog with the corresponding login error
82
+     *
83
+     * @param error The error given by the login request
84
+     */
76 85
     showErrorDialog = (error: number) =>
77 86
         this.setState({
78 87
             dialogVisible: true,
@@ -81,6 +90,10 @@ class LoginScreen extends React.Component<Props, State> {
81 90
 
82 91
     hideErrorDialog = () => this.setState({dialogVisible: false});
83 92
 
93
+    /**
94
+     * Navigates to the screen specified in navigation parameters or simply go back tha stack.
95
+     * Saves in user preferences to not show the login banner again.
96
+     */
84 97
     handleSuccess = () => {
85 98
         // Do not show the login banner again
86 99
         AsyncStorageManager.getInstance().savePref(
@@ -93,32 +106,75 @@ class LoginScreen extends React.Component<Props, State> {
93 106
             this.props.navigation.replace(this.nextScreen);
94 107
     };
95 108
 
109
+    /**
110
+     * Navigates to the Amicale website screen with the reset password link as navigation parameters
111
+     */
96 112
     onResetPasswordClick = () => this.props.navigation.navigate('amicale-website', {path: RESET_PASSWORD_PATH});
97 113
 
114
+    /**
115
+     * The user has unfocused the input, his email is ready to be validated
116
+     */
98 117
     validateEmail = () => this.setState({isEmailValidated: true});
99 118
 
119
+    /**
120
+     * Checks if the entered email is valid (matches the regex)
121
+     *
122
+     * @returns {boolean}
123
+     */
100 124
     isEmailValid() {
101 125
         return emailRegex.test(this.state.email);
102 126
     }
103 127
 
128
+    /**
129
+     * Checks if we should tell the user his email is invalid.
130
+     * We should only show this if his email is invalid and has been checked when un-focusing the input
131
+     *
132
+     * @returns {boolean|boolean}
133
+     */
104 134
     shouldShowEmailError() {
105 135
         return this.state.isEmailValidated && !this.isEmailValid();
106 136
     }
107 137
 
138
+    /**
139
+     * The user has unfocused the input, his password is ready to be validated
140
+     */
108 141
     validatePassword = () => this.setState({isPasswordValidated: true});
109 142
 
143
+    /**
144
+     * Checks if the user has entered a password
145
+     *
146
+     * @returns {boolean}
147
+     */
110 148
     isPasswordValid() {
111 149
         return this.state.password !== '';
112 150
     }
113 151
 
152
+    /**
153
+     * Checks if we should tell the user his password is invalid.
154
+     * We should only show this if his password is invalid and has been checked when un-focusing the input
155
+     *
156
+     * @returns {boolean|boolean}
157
+     */
114 158
     shouldShowPasswordError() {
115 159
         return this.state.isPasswordValidated && !this.isPasswordValid();
116 160
     }
117 161
 
162
+    /**
163
+     * If the email and password are valid, and we are not loading a request, then the login button can be enabled
164
+     *
165
+     * @returns {boolean}
166
+     */
118 167
     shouldEnableLogin() {
119 168
         return this.isEmailValid() && this.isPasswordValid() && !this.state.loading;
120 169
     }
121 170
 
171
+    /**
172
+     * Called when the user input changes in the email or password field.
173
+     * This saves the new value in the State and disabled input validation (to prevent errors to show while typing)
174
+     *
175
+     * @param isEmail True if the field is the email field
176
+     * @param value The new field value
177
+     */
122 178
     onInputChange(isEmail: boolean, value: string) {
123 179
         if (isEmail) {
124 180
             this.setState({
@@ -133,8 +189,23 @@ class LoginScreen extends React.Component<Props, State> {
133 189
         }
134 190
     }
135 191
 
136
-    onEmailSubmit = () => this.passwordInputRef.focus();
192
+    /**
193
+     * Focuses the password field when the email field is done
194
+     *
195
+     * @returns {*}
196
+     */
197
+    onEmailSubmit = () => {
198
+        if (this.passwordInputRef.current != null)
199
+            this.passwordInputRef.current.focus();
200
+    }
137 201
 
202
+    /**
203
+     * Called when the user clicks on login or finishes to type his password.
204
+     *
205
+     * Checks if we should allow the user to login,
206
+     * then makes the login request and enters a loading state until the request finishes
207
+     *
208
+     */
138 209
     onSubmit = () => {
139 210
         if (this.shouldEnableLogin()) {
140 211
             this.setState({loading: true});
@@ -147,6 +218,11 @@ class LoginScreen extends React.Component<Props, State> {
147 218
         }
148 219
     };
149 220
 
221
+    /**
222
+     * Gets the form input
223
+     *
224
+     * @returns {*}
225
+     */
150 226
     getFormInput() {
151 227
         return (
152 228
             <View>
@@ -173,9 +249,7 @@ class LoginScreen extends React.Component<Props, State> {
173 249
                     {i18n.t("loginScreen.emailError")}
174 250
                 </HelperText>
175 251
                 <TextInput
176
-                    ref={(ref) => {
177
-                        this.passwordInputRef = ref;
178
-                    }}
252
+                    ref={this.passwordInputRef}
179 253
                     label={i18n.t("loginScreen.password")}
180 254
                     mode='outlined'
181 255
                     value={this.state.password}
@@ -201,6 +275,10 @@ class LoginScreen extends React.Component<Props, State> {
201 275
         );
202 276
     }
203 277
 
278
+    /**
279
+     * Gets the card containing the input form
280
+     * @returns {*}
281
+     */
204 282
     getMainCard() {
205 283
         return (
206 284
             <Card style={styles.card}>
@@ -239,6 +317,11 @@ class LoginScreen extends React.Component<Props, State> {
239 317
         );
240 318
     }
241 319
 
320
+    /**
321
+     * Gets the card containing the information about the Amicale account
322
+     *
323
+     * @returns {*}
324
+     */
242 325
     getSecondaryCard() {
243 326
         return (
244 327
             <Card style={styles.card}>

+ 54
- 12
src/screens/Amicale/ProfileScreen.js View File

@@ -12,10 +12,12 @@ import {Collapsible} from "react-navigation-collapsible";
12 12
 import {withCollapsible} from "../../utils/withCollapsible";
13 13
 import type {cardList} from "../../components/Lists/CardList/CardList";
14 14
 import CardList from "../../components/Lists/CardList/CardList";
15
+import {StackNavigationProp} from "@react-navigation/stack";
16
+import type {CustomTheme} from "../../managers/ThemeManager";
15 17
 
16 18
 type Props = {
17
-    navigation: Object,
18
-    theme: Object,
19
+    navigation: StackNavigationProp,
20
+    theme: CustomTheme,
19 21
     collapsibleStack: Collapsible,
20 22
 }
21 23
 
@@ -23,6 +25,23 @@ type State = {
23 25
     dialogVisible: boolean,
24 26
 }
25 27
 
28
+type ProfileData = {
29
+    first_name: string,
30
+    last_name: string,
31
+    email: string,
32
+    birthday: string,
33
+    phone: string,
34
+    branch: string,
35
+    link: string,
36
+    validity: boolean,
37
+    clubs: Array<Club>,
38
+}
39
+type Club = {
40
+    id: number,
41
+    name: string,
42
+    is_manager: boolean,
43
+}
44
+
26 45
 const CLUBS_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Clubs.png";
27 46
 const VOTE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Vote.png";
28 47
 
@@ -34,9 +53,9 @@ class ProfileScreen extends React.Component<Props, State> {
34 53
         dialogVisible: false,
35 54
     };
36 55
 
37
-    data: Object;
56
+    data: ProfileData;
38 57
 
39
-    flatListData: Array<Object>;
58
+    flatListData: Array<{ id: string }>;
40 59
     amicaleDataset: cardList;
41 60
 
42 61
     constructor() {
@@ -79,12 +98,25 @@ class ProfileScreen extends React.Component<Props, State> {
79 98
 
80 99
     hideDisconnectDialog = () => this.setState({dialogVisible: false});
81 100
 
101
+    /**
102
+     * Gets the logout header button
103
+     *
104
+     * @returns {*}
105
+     */
82 106
     getHeaderButton = () => <MaterialHeaderButtons>
83 107
         <Item title="logout" iconName="logout" onPress={this.showDisconnectDialog}/>
84 108
     </MaterialHeaderButtons>;
85 109
 
86
-    getScreen = (data: Object) => {
87
-        this.data = data[0];
110
+    /**
111
+     * Gets the main screen component with the fetched data
112
+     *
113
+     * @param data The data fetched from the server
114
+     * @returns {*}
115
+     */
116
+    getScreen = (data: Array<{ [key: string]: any } | null>) => {
117
+        if (data[0] != null) {
118
+            this.data = data[0];
119
+        }
88 120
         const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
89 121
         return (
90 122
             <View style={{flex: 1}}>
@@ -109,7 +141,7 @@ class ProfileScreen extends React.Component<Props, State> {
109 141
         )
110 142
     };
111 143
 
112
-    getRenderItem = ({item}: Object) => {
144
+    getRenderItem = ({item}: { item: { id: string } }) => {
113 145
         switch (item.id) {
114 146
             case '0':
115 147
                 return this.getWelcomeCard();
@@ -122,6 +154,11 @@ class ProfileScreen extends React.Component<Props, State> {
122 154
         }
123 155
     };
124 156
 
157
+    /**
158
+     * Gets the list of services available with the Amicale account
159
+     *
160
+     * @returns {*}
161
+     */
125 162
     getServicesList() {
126 163
         return (
127 164
             <CardList
@@ -131,12 +168,17 @@ class ProfileScreen extends React.Component<Props, State> {
131 168
         );
132 169
     }
133 170
 
171
+    /**
172
+     * Gets a card welcoming the user to his account
173
+     *
174
+     * @returns {*}
175
+     */
134 176
     getWelcomeCard() {
135 177
         return (
136 178
             <Card style={styles.card}>
137 179
                 <Card.Title
138 180
                     title={i18n.t("profileScreen.welcomeTitle", {name: this.data.first_name})}
139
-                    left={(props) => <Avatar.Image
181
+                    left={() => <Avatar.Image
140 182
                         size={64}
141 183
                         source={ICON_AMICALE}
142 184
                         style={{backgroundColor: 'transparent',}}
@@ -340,7 +382,7 @@ class ProfileScreen extends React.Component<Props, State> {
340 382
      * @param item The club to render
341 383
      * @return {*}
342 384
      */
343
-    clubListItem = ({item}: Object) => {
385
+    clubListItem = ({item}: { item: Club }) => {
344 386
         const onPress = () => this.openClubDetailsScreen(item.id);
345 387
         let description = i18n.t("profileScreen.isMember");
346 388
         let icon = (props) => <List.Icon {...props} icon="chevron-right"/>;
@@ -356,9 +398,9 @@ class ProfileScreen extends React.Component<Props, State> {
356 398
         />;
357 399
     };
358 400
 
359
-    clubKeyExtractor = (item: Object) => item.name;
401
+    clubKeyExtractor = (item: Club) => item.name;
360 402
 
361
-    sortClubList = (a: Object, b: Object) => a.is_manager ? -1 : 1;
403
+    sortClubList = (a: Club, b: Club) => a.is_manager ? -1 : 1;
362 404
 
363 405
     /**
364 406
      * Renders the list of clubs the user is part of
@@ -366,7 +408,7 @@ class ProfileScreen extends React.Component<Props, State> {
366 408
      * @param list The club list
367 409
      * @return {*}
368 410
      */
369
-    getClubList(list: Array<Object>) {
411
+    getClubList(list: Array<Club>) {
370 412
         list.sort(this.sortClubList);
371 413
         return (
372 414
             //$FlowFixMe

+ 36
- 7
src/screens/Amicale/VoteScreen.js View File

@@ -9,6 +9,7 @@ import VoteTease from "../../components/Amicale/Vote/VoteTease";
9 9
 import VoteSelect from "../../components/Amicale/Vote/VoteSelect";
10 10
 import VoteResults from "../../components/Amicale/Vote/VoteResults";
11 11
 import VoteWait from "../../components/Amicale/Vote/VoteWait";
12
+import {StackNavigationProp} from "@react-navigation/stack";
12 13
 
13 14
 export type team = {
14 15
     id: number,
@@ -86,13 +87,16 @@ type objectVoteDates = {
86 87
 const MIN_REFRESH_TIME = 5 * 1000;
87 88
 
88 89
 type Props = {
89
-    navigation: Object
90
+    navigation: StackNavigationProp
90 91
 }
91 92
 
92 93
 type State = {
93 94
     hasVoted: boolean,
94 95
 }
95 96
 
97
+/**
98
+ * Screen displaying vote information and controls
99
+ */
96 100
 export default class VoteScreen extends React.Component<Props, State> {
97 101
 
98 102
     state = {
@@ -107,7 +111,7 @@ export default class VoteScreen extends React.Component<Props, State> {
107 111
     today: Date;
108 112
 
109 113
     mainFlatListData: Array<{ key: string }>;
110
-    lastRefresh: Date;
114
+    lastRefresh: Date | null;
111 115
 
112 116
     authRef: { current: null | AuthenticatedScreen };
113 117
 
@@ -116,22 +120,30 @@ export default class VoteScreen extends React.Component<Props, State> {
116 120
         this.hasVoted = false;
117 121
         this.today = new Date();
118 122
         this.authRef = React.createRef();
123
+        this.lastRefresh = null;
119 124
         this.mainFlatListData = [
120 125
             {key: 'main'},
121 126
             {key: 'info'},
122 127
         ]
123 128
     }
124 129
 
130
+    /**
131
+     * Reloads vote data if last refresh delta is smaller than the minimum refresh time
132
+     */
125 133
     reloadData = () => {
126 134
         let canRefresh;
127
-        if (this.lastRefresh !== undefined)
128
-            canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) > MIN_REFRESH_TIME;
135
+        const lastRefresh = this.lastRefresh;
136
+        if (lastRefresh != null)
137
+            canRefresh = (new Date().getTime() - lastRefresh.getTime()) > MIN_REFRESH_TIME;
129 138
         else
130 139
             canRefresh = true;
131 140
         if (canRefresh && this.authRef.current != null)
132 141
             this.authRef.current.reload()
133 142
     };
134 143
 
144
+    /**
145
+     * Generates the objects containing string and Date representations of key vote dates
146
+     */
135 147
     generateDateObject() {
136 148
         const strings = this.datesString;
137 149
         if (strings != null) {
@@ -152,6 +164,16 @@ export default class VoteScreen extends React.Component<Props, State> {
152 164
             this.dates = null;
153 165
     }
154 166
 
167
+    /**
168
+     * Gets the string representation of the given date.
169
+     *
170
+     * If the given date is the same day as today, only return the tile.
171
+     * Otherwise, return the full date.
172
+     *
173
+     * @param date The Date object representation of the wanted date
174
+     * @param dateString The string representation of the wanted date
175
+     * @returns {string}
176
+     */
155 177
     getDateString(date: Date, dateString: string): string {
156 178
         if (this.today.getDate() === date.getDate()) {
157 179
             const str = getTimeOnlyString(dateString);
@@ -176,7 +198,7 @@ export default class VoteScreen extends React.Component<Props, State> {
176 198
         return this.dates != null && this.today > this.dates.date_result_begin;
177 199
     }
178 200
 
179
-    mainRenderItem = ({item}: Object) => {
201
+    mainRenderItem = ({item}: { item: { key: string } }) => {
180 202
         if (item.key === 'info')
181 203
             return <VoteTitle/>;
182 204
         else if (item.key === 'main' && this.dates != null)
@@ -190,8 +212,8 @@ export default class VoteScreen extends React.Component<Props, State> {
190 212
         // data[1] = FAKE_DATE;
191 213
         this.lastRefresh = new Date();
192 214
 
193
-        const teams : teamResponse | null = data[0];
194
-        const dateStrings : stringVoteDates | null = data[1];
215
+        const teams: teamResponse | null = data[0];
216
+        const dateStrings: stringVoteDates | null = data[1];
195 217
 
196 218
         if (dateStrings != null && dateStrings.date_begin == null)
197 219
             this.datesString = null;
@@ -282,6 +304,13 @@ export default class VoteScreen extends React.Component<Props, State> {
282 304
                          isVoteRunning={this.isVoteRunning()}/>;
283 305
     }
284 306
 
307
+    /**
308
+     * Renders the authenticated screen.
309
+     *
310
+     * Teams and dates are not mandatory to allow showing the information box even if api requests fail
311
+     *
312
+     * @returns {*}
313
+     */
285 314
     render() {
286 315
         return (
287 316
             <AuthenticatedScreen

+ 24
- 15
src/screens/Home/FeedItemScreen.js View File

@@ -7,29 +7,29 @@ import ImageModal from 'react-native-image-modal';
7 7
 import Autolink from "react-native-autolink";
8 8
 import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
9 9
 import CustomTabBar from "../../components/Tabbar/CustomTabBar";
10
+import {StackNavigationProp} from "@react-navigation/stack";
11
+import type {feedItem} from "./HomeScreen";
10 12
 
11 13
 type Props = {
12
-    navigation: Object,
13
-    route: Object
14
+    navigation: StackNavigationProp,
15
+    route: { params: { data: feedItem, date: string } }
14 16
 };
15 17
 
16 18
 const ICON_AMICALE = require('../../../assets/amicale.png');
17 19
 const NAME_AMICALE = 'Amicale INSA Toulouse';
20
+
18 21
 /**
19
- * Class defining a planning event information page.
22
+ * Class defining a feed item page.
20 23
  */
21 24
 class FeedItemScreen extends React.Component<Props> {
22 25
 
23
-    displayData: Object;
26
+    displayData: feedItem;
24 27
     date: string;
25 28
 
26
-    colors: Object;
27
-
28 29
     constructor(props) {
29 30
         super(props);
30
-        this.colors = props.theme.colors;
31
-        this.displayData = this.props.route.params.data;
32
-        this.date = this.props.route.params.date;
31
+        this.displayData = props.route.params.data;
32
+        this.date = props.route.params.date;
33 33
     }
34 34
 
35 35
     componentDidMount() {
@@ -38,16 +38,29 @@ class FeedItemScreen extends React.Component<Props> {
38 38
         });
39 39
     }
40 40
 
41
+    /**
42
+     * Opens the feed item out link in browser or compatible app
43
+     */
41 44
     onOutLinkPress = () => {
42 45
         Linking.openURL(this.displayData.permalink_url);
43 46
     };
44 47
 
48
+    /**
49
+     * Gets the out link header button
50
+     *
51
+     * @returns {*}
52
+     */
45 53
     getHeaderButton = () => {
46 54
         return <MaterialHeaderButtons>
47 55
             <Item title="main" iconName={'facebook'} color={"#2e88fe"} onPress={this.onOutLinkPress}/>
48 56
         </MaterialHeaderButtons>;
49 57
     };
50 58
 
59
+    /**
60
+     * Gets the Amicale INSA avatar
61
+     *
62
+     * @returns {*}
63
+     */
51 64
     getAvatar() {
52 65
         return (
53 66
             <Avatar.Image size={48} source={ICON_AMICALE}
@@ -55,8 +68,8 @@ class FeedItemScreen extends React.Component<Props> {
55 68
         );
56 69
     }
57 70
 
58
-    getContent() {
59
-        const hasImage = this.displayData.full_picture !== '' && this.displayData.full_picture !== undefined;
71
+    render() {
72
+        const hasImage = this.displayData.full_picture !== '' && this.displayData.full_picture != null;
60 73
         return (
61 74
             <ScrollView style={{margin: 5,}}>
62 75
                 <Card.Title
@@ -89,10 +102,6 @@ class FeedItemScreen extends React.Component<Props> {
89 102
             </ScrollView>
90 103
         );
91 104
     }
92
-
93
-    render() {
94
-        return this.getContent();
95
-    }
96 105
 }
97 106
 
98 107
 export default withTheme(FeedItemScreen);

+ 34
- 11
src/screens/Home/HomeScreen.js View File

@@ -111,8 +111,6 @@ type State = {
111 111
  */
112 112
 class HomeScreen extends React.Component<Props, State> {
113 113
 
114
-    colors: Object;
115
-
116 114
     isLoggedIn: boolean | null;
117 115
 
118 116
     fabRef: { current: null | AnimatedFAB };
@@ -125,7 +123,6 @@ class HomeScreen extends React.Component<Props, State> {
125 123
 
126 124
     constructor(props) {
127 125
         super(props);
128
-        this.colors = props.theme.colors;
129 126
         this.fabRef = React.createRef();
130 127
         this.currentNewFeed = [];
131 128
         this.isLoggedIn = null;
@@ -155,6 +152,9 @@ class HomeScreen extends React.Component<Props, State> {
155 152
         })
156 153
     }
157 154
 
155
+    /**
156
+     * Updates login state and navigation parameters on screen focus
157
+     */
158 158
     onScreenFocus = () => {
159 159
         if (ConnectionManager.getInstance().isLoggedIn() !== this.isLoggedIn) {
160 160
             this.isLoggedIn = ConnectionManager.getInstance().isLoggedIn();
@@ -169,6 +169,9 @@ class HomeScreen extends React.Component<Props, State> {
169 169
         this.handleNavigationParams();
170 170
     };
171 171
 
172
+    /**
173
+     * Navigates to the a new screen if navigation parameters specify one
174
+     */
172 175
     handleNavigationParams = () => {
173 176
         if (this.props.route.params != null) {
174 177
             if (this.props.route.params.nextScreen != null) {
@@ -179,6 +182,11 @@ class HomeScreen extends React.Component<Props, State> {
179 182
         }
180 183
     };
181 184
 
185
+    /**
186
+     * Gets header buttons based on login state
187
+     *
188
+     * @returns {*}
189
+     */
182 190
     getHeaderButton = () => {
183 191
         let onPressLog = () => this.props.navigation.navigate("login", {nextScreen: "profile"});
184 192
         let logIcon = "login";
@@ -262,7 +270,7 @@ class HomeScreen extends React.Component<Props, State> {
262 270
                         id: 'washers',
263 271
                         data: dashboardData == null ? 0 : dashboardData.available_machines.washers,
264 272
                         icon: 'washing-machine',
265
-                        color: this.colors.proxiwashColor,
273
+                        color: this.props.theme.colors.proxiwashColor,
266 274
                         onPress: this.onProxiwashClick,
267 275
                         isAvailable: dashboardData == null ? false : dashboardData.available_machines.washers > 0
268 276
                     },
@@ -270,7 +278,7 @@ class HomeScreen extends React.Component<Props, State> {
270 278
                         id: 'dryers',
271 279
                         data: dashboardData == null ? 0 : dashboardData.available_machines.dryers,
272 280
                         icon: 'tumble-dryer',
273
-                        color: this.colors.proxiwashColor,
281
+                        color: this.props.theme.colors.proxiwashColor,
274 282
                         onPress: this.onProxiwashClick,
275 283
                         isAvailable: dashboardData == null ? false : dashboardData.available_machines.dryers > 0
276 284
                     },
@@ -278,7 +286,7 @@ class HomeScreen extends React.Component<Props, State> {
278 286
                         id: 'available_tutorials',
279 287
                         data: dashboardData == null ? 0 : dashboardData.available_tutorials,
280 288
                         icon: 'school',
281
-                        color: this.colors.tutorinsaColor,
289
+                        color: this.props.theme.colors.tutorinsaColor,
282 290
                         onPress: this.onTutorInsaClick,
283 291
                         isAvailable: dashboardData == null ? false : dashboardData.available_tutorials > 0
284 292
                     },
@@ -286,7 +294,7 @@ class HomeScreen extends React.Component<Props, State> {
286 294
                         id: 'proximo_articles',
287 295
                         data: dashboardData == null ? 0 : dashboardData.proximo_articles,
288 296
                         icon: 'shopping',
289
-                        color: this.colors.proximoColor,
297
+                        color: this.props.theme.colors.proximoColor,
290 298
                         onPress: this.onProximoClick,
291 299
                         isAvailable: dashboardData == null ? false : dashboardData.proximo_articles > 0
292 300
                     },
@@ -294,7 +302,7 @@ class HomeScreen extends React.Component<Props, State> {
294 302
                         id: 'today_menu',
295 303
                         data: dashboardData == null ? [] : dashboardData.today_menu,
296 304
                         icon: 'silverware-fork-knife',
297
-                        color: this.colors.menuColor,
305
+                        color: this.props.theme.colors.menuColor,
298 306
                         onPress: this.onMenuClick,
299 307
                         isAvailable: dashboardData == null ? false : dashboardData.today_menu.length > 0
300 308
                     },
@@ -324,6 +332,11 @@ class HomeScreen extends React.Component<Props, State> {
324 332
             return this.getDashboardActions();
325 333
     }
326 334
 
335
+    /**
336
+     * Gets a dashboard item with action buttons
337
+     *
338
+     * @returns {*}
339
+     */
327 340
     getDashboardActions() {
328 341
         return <ActionsDashBoardItem {...this.props} isLoggedIn={this.isLoggedIn}/>;
329 342
     }
@@ -446,7 +459,7 @@ class HomeScreen extends React.Component<Props, State> {
446 459
     onEventContainerClick = () => this.props.navigation.navigate('planning');
447 460
 
448 461
     /**
449
-     * Gets the event render item.
462
+     * Gets the event dashboard render item.
450 463
      * If a preview is available, it will be rendered inside
451 464
      *
452 465
      * @param content
@@ -473,6 +486,12 @@ class HomeScreen extends React.Component<Props, State> {
473 486
         );
474 487
     }
475 488
 
489
+    /**
490
+     * Gets a dashboard shortcut item
491
+     *
492
+     * @param item
493
+     * @returns {*}
494
+     */
476 495
     dashboardRowRenderItem = ({item}: { item: dashboardSmallItem }) => {
477 496
         return (
478 497
             <SquareDashboardItem
@@ -486,7 +505,7 @@ class HomeScreen extends React.Component<Props, State> {
486 505
     };
487 506
 
488 507
     /**
489
-     * Gets a classic dashboard item.
508
+     * Gets a dashboard item with a row of shortcut buttons.
490 509
      *
491 510
      * @param content
492 511
      * @return {*}
@@ -553,7 +572,7 @@ class HomeScreen extends React.Component<Props, State> {
553 572
 
554 573
     /**
555 574
      * Callback used when closing the banner.
556
-     * This hides the banner and saves to preferences to prevent it from reopening
575
+     * This hides the banner and saves to preferences to prevent it from reopening.
557 576
      */
558 577
     onHideBanner = () => {
559 578
         this.setState({bannerVisible: false});
@@ -563,6 +582,10 @@ class HomeScreen extends React.Component<Props, State> {
563 582
         );
564 583
     };
565 584
 
585
+    /**
586
+     * Callback when pressing the login button on the banner.
587
+     * This hides the banner and takes the user to the login page.
588
+     */
566 589
     onLoginBanner = () => {
567 590
         this.onHideBanner();
568 591
         this.props.navigation.navigate("login", {nextScreen: "profile"});

+ 38
- 0
src/screens/Home/ScannerScreen.js View File

@@ -41,6 +41,9 @@ class ScannerScreen extends React.Component<Props, State> {
41 41
         this.requestPermissions();
42 42
     }
43 43
 
44
+    /**
45
+     * Requests permission to use the camera
46
+     */
44 47
     requestPermissions = () => {
45 48
         if (Platform.OS === 'android')
46 49
             request(PERMISSIONS.ANDROID.CAMERA).then(this.updatePermissionStatus)
@@ -48,8 +51,19 @@ class ScannerScreen extends React.Component<Props, State> {
48 51
             request(PERMISSIONS.IOS.CAMERA).then(this.updatePermissionStatus)
49 52
     };
50 53
 
54
+    /**
55
+     * Updates the state permission status
56
+     *
57
+     * @param result
58
+     */
51 59
     updatePermissionStatus = (result) => this.setState({hasPermission: result === RESULTS.GRANTED});
52 60
 
61
+    /**
62
+     * Opens scanned link if it is a valid app link or shows and error dialog
63
+     *
64
+     * @param type The barcode type
65
+     * @param data The scanned value
66
+     */
53 67
     handleCodeScanned = ({type, data}) => {
54 68
         if (!URLHandler.isUrlValid(data))
55 69
             this.showErrorDialog();
@@ -59,6 +73,11 @@ class ScannerScreen extends React.Component<Props, State> {
59 73
         }
60 74
     };
61 75
 
76
+    /**
77
+     * Gets a view asking user for permission to use the camera
78
+     *
79
+     * @returns {*}
80
+     */
62 81
     getPermissionScreen() {
63 82
         return <View style={{marginLeft: 10, marginRight: 10}}>
64 83
             <Text>{i18n.t("scannerScreen.errorPermission")}</Text>
@@ -77,6 +96,9 @@ class ScannerScreen extends React.Component<Props, State> {
77 96
         </View>
78 97
     }
79 98
 
99
+    /**
100
+     * Shows a dialog indicating how to use the scanner
101
+     */
80 102
     showHelpDialog = () => {
81 103
         this.setState({
82 104
             dialogVisible: true,
@@ -86,6 +108,9 @@ class ScannerScreen extends React.Component<Props, State> {
86 108
         });
87 109
     };
88 110
 
111
+    /**
112
+     * Shows a loading dialog
113
+     */
89 114
     showOpeningDialog = () => {
90 115
         this.setState({
91 116
             loading: true,
@@ -93,6 +118,9 @@ class ScannerScreen extends React.Component<Props, State> {
93 118
         });
94 119
     };
95 120
 
121
+    /**
122
+     * Shows a dialog indicating the user the scanned code was invalid
123
+     */
96 124
     showErrorDialog() {
97 125
         this.setState({
98 126
             dialogVisible: true,
@@ -102,11 +130,21 @@ class ScannerScreen extends React.Component<Props, State> {
102 130
         });
103 131
     }
104 132
 
133
+    /**
134
+     * Hide any dialog
135
+     */
105 136
     onDialogDismiss = () => this.setState({
106 137
         dialogVisible: false,
107 138
         scanned: false,
108 139
     });
109 140
 
141
+    /**
142
+     * Gets a view with the scanner.
143
+     * This scanner uses the back camera, can only scan qr codes and has a square mask on the center.
144
+     * The mask is only for design purposes as a code is scanned as soon as it enters the camera view
145
+     *
146
+     * @returns {*}
147
+     */
110 148
     getScanner() {
111 149
         return (
112 150
             <RNCamera

+ 2
- 2
src/utils/Search.js View File

@@ -32,10 +32,10 @@ export function stringMatchQuery(str: string, query: string) {
32 32
  * Checks if the given arrays have an item in common
33 33
  *
34 34
  * @param filter The filter array
35
- * @param categories The item's categories array
35
+ * @param categories The item's categories tuple
36 36
  * @returns {boolean} True if at least one entry is in both arrays
37 37
  */
38
-export function isItemInCategoryFilter(filter: Array<string>, categories: Array<string>) {
38
+export function isItemInCategoryFilter(filter: Array<number>, categories: [number, number]) {
39 39
     for (const category of categories) {
40 40
         if (filter.indexOf(category) !== -1)
41 41
             return true;

Loading…
Cancel
Save