Browse Source

Created a loading dialog component to handle async requests

Arnaud Vergnet 4 years ago
parent
commit
b2891ddeea

+ 25
- 63
src/components/Amicale/LogoutDialog.js View File

@@ -1,9 +1,9 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {ActivityIndicator, Button, Dialog, Paragraph, Portal, withTheme} from 'react-native-paper';
5
-import ConnectionManager from "../../managers/ConnectionManager";
6 4
 import i18n from 'i18n-js';
5
+import LoadingConfirmDialog from "../Custom/LoadingConfirmDialog";
6
+import ConnectionManager from "../../managers/ConnectionManager";
7 7
 
8 8
 type Props = {
9 9
     navigation: Object,
@@ -11,73 +11,35 @@ type Props = {
11 11
     onDismiss: Function,
12 12
 }
13 13
 
14
-type State = {
15
-    loading: boolean,
16
-}
17
-
18
-class LogoutDialog extends React.PureComponent<Props, State> {
19
-
20
-    colors: Object;
21
-
22
-    state = {
23
-        loading: false,
24
-    };
25
-
26
-    constructor(props) {
27
-        super(props);
28
-        this.colors = props.theme.colors;
29
-    }
30
-
31
-    onClickAccept = () => {
32
-        this.setState({loading: true});
33
-        ConnectionManager.getInstance().disconnect()
34
-            .then(() => {
35
-                this.props.onDismiss();
36
-                this.setState({loading: false});
37
-                this.props.navigation.reset({
38
-                    index: 0,
39
-                    routes: [{name: 'Main'}],
14
+class LogoutDialog extends React.PureComponent<Props> {
15
+
16
+    onClickAccept = async () => {
17
+        return new Promise((resolve, reject) => {
18
+            ConnectionManager.getInstance().disconnect()
19
+                .then(() => {
20
+                    this.props.navigation.reset({
21
+                        index: 0,
22
+                        routes: [{name: 'Main'}],
23
+                    });
24
+                    this.props.onDismiss();
25
+                    resolve();
40 26
                 });
41
-            });
42
-    };
43
-
44
-    onDismiss = () => {
45
-        if (!this.state.loading)
46
-            this.props.onDismiss();
27
+        });
47 28
     };
48 29
 
49 30
     render() {
50 31
         return (
51
-            <Portal>
52
-                <Dialog
53
-                    visible={this.props.visible}
54
-                    onDismiss={this.onDismiss}>
55
-                    <Dialog.Title>
56
-                        {this.state.loading
57
-                            ? i18n.t("dialog.disconnect.titleLoading")
58
-                            : i18n.t("dialog.disconnect.title")}
59
-                    </Dialog.Title>
60
-                    <Dialog.Content>
61
-                        {this.state.loading
62
-                            ? <ActivityIndicator
63
-                                animating={true}
64
-                                size={'large'}
65
-                                color={this.colors.primary}/>
66
-                            : <Paragraph>{i18n.t("dialog.disconnect.message")}</Paragraph>
67
-                        }
68
-                    </Dialog.Content>
69
-                    {this.state.loading
70
-                        ? null
71
-                        : <Dialog.Actions>
72
-                            <Button onPress={this.onDismiss} style={{marginRight: 10}}>{i18n.t("dialog.cancel")}</Button>
73
-                            <Button onPress={this.onClickAccept}>{i18n.t("dialog.yes")}</Button>
74
-                        </Dialog.Actions>
75
-                    }
76
-
77
-                </Dialog>
78
-            </Portal>
32
+            <LoadingConfirmDialog
33
+                {...this.props}
34
+                visible={this.props.visible}
35
+                onDismiss={this.props.onDismiss}
36
+                onAccept={this.onClickAccept}
37
+                title={i18n.t("dialog.disconnect.title")}
38
+                titleLoading={i18n.t("dialog.disconnect.titleLoading")}
39
+                message={i18n.t("dialog.disconnect.message")}
40
+            />
79 41
         );
80 42
     }
81 43
 }
82 44
 
83
-export default withTheme(LogoutDialog);
45
+export default LogoutDialog;

+ 74
- 0
src/components/Custom/LoadingConfirmDialog.js View File

@@ -0,0 +1,74 @@
1
+import * as React from 'react';
2
+import {ActivityIndicator, Button, Dialog, Paragraph, Portal} from 'react-native-paper';
3
+import i18n from "i18n-js";
4
+
5
+type Props = {
6
+    visible: boolean,
7
+    onDismiss: Function,
8
+    onAccept: Function, // async function to be executed
9
+    title: string,
10
+    titleLoading: string,
11
+    message: string,
12
+}
13
+
14
+type State = {
15
+    loading: boolean,
16
+}
17
+
18
+class LoadingConfirmDialog extends React.PureComponent<Props, State> {
19
+
20
+    state = {
21
+        loading: false,
22
+    };
23
+
24
+    onClickAccept = () => {
25
+        this.setState({loading: true});
26
+        this.props.onAccept()
27
+            .then(() => {
28
+                //Wait for fade out animations to finish before hiding loading
29
+                setTimeout(() => {
30
+                    this.setState({loading: false})
31
+                }, 200);
32
+
33
+            });
34
+    };
35
+
36
+    onDismiss = () => {
37
+        if (!this.state.loading)
38
+            this.props.onDismiss();
39
+    };
40
+
41
+    render() {
42
+        return (
43
+            <Portal>
44
+                <Dialog
45
+                    visible={this.props.visible}
46
+                    onDismiss={this.onDismiss}>
47
+                    <Dialog.Title>
48
+                        {this.state.loading
49
+                            ? this.props.titleLoading
50
+                            : this.props.title}
51
+                    </Dialog.Title>
52
+                    <Dialog.Content>
53
+                        {this.state.loading
54
+                            ? <ActivityIndicator
55
+                                animating={true}
56
+                                size={'large'}/>
57
+                            : <Paragraph>{this.props.message}</Paragraph>
58
+                        }
59
+                    </Dialog.Content>
60
+                    {this.state.loading
61
+                        ? null
62
+                        : <Dialog.Actions>
63
+                            <Button onPress={this.onDismiss}
64
+                                    style={{marginRight: 10}}>{i18n.t("dialog.cancel")}</Button>
65
+                            <Button onPress={this.onClickAccept}>{i18n.t("dialog.yes")}</Button>
66
+                        </Dialog.Actions>
67
+                    }
68
+                </Dialog>
69
+            </Portal>
70
+        );
71
+    }
72
+}
73
+
74
+export default LoadingConfirmDialog;

+ 17
- 2
src/managers/ConnectionManager.js View File

@@ -182,16 +182,31 @@ export default class ConnectionManager {
182 182
         return valid;
183 183
     }
184 184
 
185
-    async authenticatedRequest(path: string) {
185
+    generatePostArguments(keys: Array<string>, values: Array<string>) {
186
+        let data = {};
187
+        for (let i = 0; i < keys.length; i++) {
188
+            data[keys[i]] = values[i];
189
+        }
190
+        return data;
191
+    }
192
+
193
+    async authenticatedRequest(path: string, keys: Array<string>, values: Array<any>) {
186 194
         return new Promise((resolve, reject) => {
187 195
             if (this.getToken() !== null) {
196
+                let data = {};
197
+                if (keys !== undefined && values !== undefined && keys.length === values.length)
198
+                    data = this.generatePostArguments(keys, values);
199
+                console.log(data);
188 200
                 fetch(API_ENDPOINT + path, {
189 201
                     method: 'POST',
190 202
                     headers: new Headers({
191 203
                         'Accept': 'application/json',
192 204
                         'Content-Type': 'application/json',
193 205
                     }),
194
-                    body: JSON.stringify({token: this.getToken()})
206
+                    body: JSON.stringify({
207
+                        token: this.getToken(),
208
+                        ...data
209
+                    })
195 210
                 }).then(async (response) => response.json())
196 211
                     .then((response: response_format) => {
197 212
                         console.log(response);

+ 52
- 18
src/screens/Amicale/VoteScreen.js View File

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {FlatList, StyleSheet} from "react-native";
4
+import {FlatList, StyleSheet, View} from "react-native";
5 5
 import {
6 6
     ActivityIndicator,
7 7
     Avatar,
@@ -16,19 +16,16 @@ import {
16 16
 } from 'react-native-paper';
17 17
 import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
18 18
 import {getTimeOnlyString, stringToDate} from "../../utils/Planning";
19
+import LoadingConfirmDialog from "../../components/Custom/LoadingConfirmDialog";
20
+import ConnectionManager from "../../managers/ConnectionManager";
19 21
 
20 22
 const ICON_AMICALE = require('../../../assets/amicale.png');
21 23
 
22
-type Props = {
23
-    navigation: Object,
24
-    theme: Object,
25
-}
26
-
27 24
 const FAKE_DATE = {
28 25
     "date_begin": "2020-04-06 21:50",
29
-    "date_end": "2020-04-06 21:50",
30
-    "date_result_begin": "2020-04-06 21:50",
31
-    "date_result_end": "2020-04-06 21:50",
26
+    "date_end": "2020-04-07 23:50",
27
+    "date_result_begin": "2020-04-07 21:50",
28
+    "date_result_end": "2020-04-07 21:50",
32 29
 };
33 30
 
34 31
 const FAKE_DATE2 = {
@@ -67,14 +64,21 @@ const FAKE_TEAMS2 = {
67 64
     ],
68 65
 };
69 66
 
67
+type Props = {
68
+    navigation: Object,
69
+    theme: Object,
70
+}
71
+
70 72
 type State = {
71 73
     selectedTeam: string,
74
+    voteDialogVisible: boolean,
72 75
 }
73 76
 
74 77
 class VoteScreen extends React.Component<Props, State> {
75 78
 
76 79
     state = {
77 80
         selectedTeam: "none",
81
+        voteDialogVisible: false,
78 82
     };
79 83
 
80 84
     colors: Object;
@@ -120,18 +124,48 @@ class VoteScreen extends React.Component<Props, State> {
120 124
         }
121 125
         this.datesString = data[1];
122 126
         this.generateDateObject();
123
-        console.log(this.teams);
124
-        console.log(this.datesString);
125 127
         return (
126
-            //$FlowFixMe
127
-            <FlatList
128
-                data={this.mainFlatListData}
129
-                extraData={this.state.selectedTeam}
130
-                renderItem={this.mainRenderItem}
131
-            />
128
+            <View>
129
+                {/*$FlowFixMe*/}
130
+                <FlatList
131
+                    data={this.mainFlatListData}
132
+                    extraData={this.state.selectedTeam}
133
+                    renderItem={this.mainRenderItem}
134
+                />
135
+                <LoadingConfirmDialog
136
+                    {...this.props}
137
+                    visible={this.state.voteDialogVisible}
138
+                    onDismiss={this.onVoteDialogDismiss}
139
+                    onAccept={this.onVoteDialogAccept}
140
+                    title={"VOTE?"}
141
+                    titleLoading={"SENDING VOTE..."}
142
+                    message={"SURE?"}
143
+                />
144
+            </View>
132 145
         );
133 146
     };
134 147
 
148
+    onVoteDialogDismiss = () => this.setState({voteDialogVisible: false});
149
+
150
+    showVoteDialog = () => this.setState({voteDialogVisible: true});
151
+
152
+    onVoteDialogAccept = async () => {
153
+        return new Promise((resolve, reject) => {
154
+            ConnectionManager.getInstance().authenticatedRequest(
155
+                "elections/vote",
156
+                ["vote"],
157
+                [parseInt(this.state.selectedTeam)])
158
+                .then(() => {
159
+                    this.onVoteDialogDismiss();
160
+                    resolve();
161
+                })
162
+                .catch(() => {
163
+                    this.onVoteDialogDismiss();
164
+                    resolve();
165
+                });
166
+        });
167
+    };
168
+
135 169
     generateDateObject() {
136 170
         this.dates = {
137 171
             date_begin: stringToDate(this.datesString.date_begin),
@@ -208,7 +242,7 @@ class VoteScreen extends React.Component<Props, State> {
208 242
     };
209 243
 
210 244
     onVotePress = () => {
211
-        console.log("vote sent");
245
+        this.showVoteDialog();
212 246
     };
213 247
 
214 248
     voteKeyExtractor = (item: Object) => item.id.toString();

Loading…
Cancel
Save