From b2891ddeea79f4f226c1a19e1411fe6e4bd0846b Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Tue, 7 Apr 2020 00:27:32 +0200 Subject: [PATCH] Created a loading dialog component to handle async requests --- src/components/Amicale/LogoutDialog.js | 86 ++++++------------- src/components/Custom/LoadingConfirmDialog.js | 74 ++++++++++++++++ src/managers/ConnectionManager.js | 19 +++- src/screens/Amicale/VoteScreen.js | 70 +++++++++++---- 4 files changed, 167 insertions(+), 82 deletions(-) create mode 100644 src/components/Custom/LoadingConfirmDialog.js diff --git a/src/components/Amicale/LogoutDialog.js b/src/components/Amicale/LogoutDialog.js index 0c32764..5c6de91 100644 --- a/src/components/Amicale/LogoutDialog.js +++ b/src/components/Amicale/LogoutDialog.js @@ -1,9 +1,9 @@ // @flow import * as React from 'react'; -import {ActivityIndicator, Button, Dialog, Paragraph, Portal, withTheme} from 'react-native-paper'; -import ConnectionManager from "../../managers/ConnectionManager"; import i18n from 'i18n-js'; +import LoadingConfirmDialog from "../Custom/LoadingConfirmDialog"; +import ConnectionManager from "../../managers/ConnectionManager"; type Props = { navigation: Object, @@ -11,73 +11,35 @@ type Props = { onDismiss: Function, } -type State = { - loading: boolean, -} +class LogoutDialog extends React.PureComponent { -class LogoutDialog extends React.PureComponent { - - colors: Object; - - state = { - loading: false, - }; - - constructor(props) { - super(props); - this.colors = props.theme.colors; - } - - onClickAccept = () => { - this.setState({loading: true}); - ConnectionManager.getInstance().disconnect() - .then(() => { - this.props.onDismiss(); - this.setState({loading: false}); - this.props.navigation.reset({ - index: 0, - routes: [{name: 'Main'}], + onClickAccept = async () => { + return new Promise((resolve, reject) => { + ConnectionManager.getInstance().disconnect() + .then(() => { + this.props.navigation.reset({ + index: 0, + routes: [{name: 'Main'}], + }); + this.props.onDismiss(); + resolve(); }); - }); - }; - - onDismiss = () => { - if (!this.state.loading) - this.props.onDismiss(); + }); }; render() { return ( - - - - {this.state.loading - ? i18n.t("dialog.disconnect.titleLoading") - : i18n.t("dialog.disconnect.title")} - - - {this.state.loading - ? - : {i18n.t("dialog.disconnect.message")} - } - - {this.state.loading - ? null - : - - - - } - - - + ); } } -export default withTheme(LogoutDialog); +export default LogoutDialog; diff --git a/src/components/Custom/LoadingConfirmDialog.js b/src/components/Custom/LoadingConfirmDialog.js new file mode 100644 index 0000000..e8aeeb6 --- /dev/null +++ b/src/components/Custom/LoadingConfirmDialog.js @@ -0,0 +1,74 @@ +import * as React from 'react'; +import {ActivityIndicator, Button, Dialog, Paragraph, Portal} from 'react-native-paper'; +import i18n from "i18n-js"; + +type Props = { + visible: boolean, + onDismiss: Function, + onAccept: Function, // async function to be executed + title: string, + titleLoading: string, + message: string, +} + +type State = { + loading: boolean, +} + +class LoadingConfirmDialog extends React.PureComponent { + + state = { + loading: false, + }; + + onClickAccept = () => { + this.setState({loading: true}); + this.props.onAccept() + .then(() => { + //Wait for fade out animations to finish before hiding loading + setTimeout(() => { + this.setState({loading: false}) + }, 200); + + }); + }; + + onDismiss = () => { + if (!this.state.loading) + this.props.onDismiss(); + }; + + render() { + return ( + + + + {this.state.loading + ? this.props.titleLoading + : this.props.title} + + + {this.state.loading + ? + : {this.props.message} + } + + {this.state.loading + ? null + : + + + + } + + + ); + } +} + +export default LoadingConfirmDialog; diff --git a/src/managers/ConnectionManager.js b/src/managers/ConnectionManager.js index 84d2a3a..e45a375 100644 --- a/src/managers/ConnectionManager.js +++ b/src/managers/ConnectionManager.js @@ -182,16 +182,31 @@ export default class ConnectionManager { return valid; } - async authenticatedRequest(path: string) { + generatePostArguments(keys: Array, values: Array) { + let data = {}; + for (let i = 0; i < keys.length; i++) { + data[keys[i]] = values[i]; + } + return data; + } + + async authenticatedRequest(path: string, keys: Array, values: Array) { return new Promise((resolve, reject) => { if (this.getToken() !== null) { + let data = {}; + if (keys !== undefined && values !== undefined && keys.length === values.length) + data = this.generatePostArguments(keys, values); + console.log(data); fetch(API_ENDPOINT + path, { method: 'POST', headers: new Headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', }), - body: JSON.stringify({token: this.getToken()}) + body: JSON.stringify({ + token: this.getToken(), + ...data + }) }).then(async (response) => response.json()) .then((response: response_format) => { console.log(response); diff --git a/src/screens/Amicale/VoteScreen.js b/src/screens/Amicale/VoteScreen.js index 6b19a98..8282303 100644 --- a/src/screens/Amicale/VoteScreen.js +++ b/src/screens/Amicale/VoteScreen.js @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; -import {FlatList, StyleSheet} from "react-native"; +import {FlatList, StyleSheet, View} from "react-native"; import { ActivityIndicator, Avatar, @@ -16,19 +16,16 @@ import { } from 'react-native-paper'; import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen"; import {getTimeOnlyString, stringToDate} from "../../utils/Planning"; +import LoadingConfirmDialog from "../../components/Custom/LoadingConfirmDialog"; +import ConnectionManager from "../../managers/ConnectionManager"; const ICON_AMICALE = require('../../../assets/amicale.png'); -type Props = { - navigation: Object, - theme: Object, -} - const FAKE_DATE = { "date_begin": "2020-04-06 21:50", - "date_end": "2020-04-06 21:50", - "date_result_begin": "2020-04-06 21:50", - "date_result_end": "2020-04-06 21:50", + "date_end": "2020-04-07 23:50", + "date_result_begin": "2020-04-07 21:50", + "date_result_end": "2020-04-07 21:50", }; const FAKE_DATE2 = { @@ -67,14 +64,21 @@ const FAKE_TEAMS2 = { ], }; +type Props = { + navigation: Object, + theme: Object, +} + type State = { selectedTeam: string, + voteDialogVisible: boolean, } class VoteScreen extends React.Component { state = { selectedTeam: "none", + voteDialogVisible: false, }; colors: Object; @@ -120,18 +124,48 @@ class VoteScreen extends React.Component { } this.datesString = data[1]; this.generateDateObject(); - console.log(this.teams); - console.log(this.datesString); return ( - //$FlowFixMe - + + {/*$FlowFixMe*/} + + + ); }; + onVoteDialogDismiss = () => this.setState({voteDialogVisible: false}); + + showVoteDialog = () => this.setState({voteDialogVisible: true}); + + onVoteDialogAccept = async () => { + return new Promise((resolve, reject) => { + ConnectionManager.getInstance().authenticatedRequest( + "elections/vote", + ["vote"], + [parseInt(this.state.selectedTeam)]) + .then(() => { + this.onVoteDialogDismiss(); + resolve(); + }) + .catch(() => { + this.onVoteDialogDismiss(); + resolve(); + }); + }); + }; + generateDateObject() { this.dates = { date_begin: stringToDate(this.datesString.date_begin), @@ -208,7 +242,7 @@ class VoteScreen extends React.Component { }; onVotePress = () => { - console.log("vote sent"); + this.showVoteDialog(); }; voteKeyExtractor = (item: Object) => item.id.toString();