From 9fc3620044b90ac63065f8936a5ceea0ce916841 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Tue, 7 Apr 2020 15:24:52 +0200 Subject: [PATCH] Moved vote cards in own component files --- src/components/Amicale/AuthenticatedScreen.js | 2 +- src/components/Amicale/Vote/VoteResults.js | 104 ++++++ src/components/Amicale/Vote/VoteSelect.js | 135 ++++++++ src/components/Amicale/Vote/VoteTease.js | 45 +++ src/components/Amicale/Vote/VoteTitle.js | 54 +++ src/components/Amicale/Vote/VoteWait.js | 73 ++++ src/managers/ConnectionManager.js | 4 +- src/screens/Amicale/VoteScreen.js | 325 ++---------------- 8 files changed, 443 insertions(+), 299 deletions(-) create mode 100644 src/components/Amicale/Vote/VoteResults.js create mode 100644 src/components/Amicale/Vote/VoteSelect.js create mode 100644 src/components/Amicale/Vote/VoteTease.js create mode 100644 src/components/Amicale/Vote/VoteTitle.js create mode 100644 src/components/Amicale/Vote/VoteWait.js diff --git a/src/components/Amicale/AuthenticatedScreen.js b/src/components/Amicale/AuthenticatedScreen.js index 1408347..3548552 100644 --- a/src/components/Amicale/AuthenticatedScreen.js +++ b/src/components/Amicale/AuthenticatedScreen.js @@ -48,7 +48,7 @@ class AuthenticatedScreen extends React.Component { this.setState({loading: true}); if (this.connectionManager.isLoggedIn()) { for (let i = 0; i < this.props.links.length; i++) { - this.connectionManager.authenticatedRequest(this.props.links[i].link) + this.connectionManager.authenticatedRequest(this.props.links[i].link, null, null) .then((data) => { this.onFinishedLoading(data, i, -1); }) diff --git a/src/components/Amicale/Vote/VoteResults.js b/src/components/Amicale/Vote/VoteResults.js new file mode 100644 index 0000000..18a6036 --- /dev/null +++ b/src/components/Amicale/Vote/VoteResults.js @@ -0,0 +1,104 @@ +// @flow + +import * as React from 'react'; +import {Avatar, Card, List, ProgressBar, Subheading, withTheme} from "react-native-paper"; +import {FlatList, StyleSheet} from "react-native"; + +type Props = { + teams: Array, + dateEnd: string, +} + +class VoteResults extends React.Component { + + totalVotes: number; + winnerId: number; + colors: Object; + + constructor(props) { + super(); + this.colors = props.theme.colors; + props.teams.sort(this.sortByVotes); + this.getTotalVotes(props.teams); + this.getWinnerId(props.teams); + } + + shouldComponentUpdate() { + return false; + } + + sortByVotes = (a: Object, b: Object) => b.votes - a.votes; + + getTotalVotes(teams: Array) { + this.totalVotes = 0; + for (let i = 0; i < teams.length; i++) { + this.totalVotes += teams[i].votes; + } + } + + getWinnerId(teams: Array) { + this.winnerId = teams[0].id; + } + + voteKeyExtractor = (item: Object) => item.id.toString(); + + resultRenderItem = ({item}: Object) => { + const isWinner = this.winnerId === item.id; + return ( + + isWinner + ? + : null} + titleStyle={{ + color: isWinner + ? this.colors.primary + : this.colors.text + }} + style={{padding: 0}} + /> + + + ); + }; + + render() { + return ( + + } + /> + + TOTAL VOTES : {this.totalVotes} + {/*$FlowFixMe*/} + + + + ); + } +} + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent' + }, +}); + +export default withTheme(VoteResults); diff --git a/src/components/Amicale/Vote/VoteSelect.js b/src/components/Amicale/Vote/VoteSelect.js new file mode 100644 index 0000000..1abd48d --- /dev/null +++ b/src/components/Amicale/Vote/VoteSelect.js @@ -0,0 +1,135 @@ +// @flow + +import * as React from 'react'; +import {Avatar, Button, Card, RadioButton} from "react-native-paper"; +import {FlatList, StyleSheet, View} from "react-native"; +import ConnectionManager from "../../../managers/ConnectionManager"; +import LoadingConfirmDialog from "../../Dialog/LoadingConfirmDialog"; +import ErrorDialog from "../../Dialog/ErrorDialog"; + +type Props = { + teams: Array, + onVoteSuccess: Function, + onVoteError: Function, +} + +type State = { + selectedTeam: string, + voteDialogVisible: boolean, + errorDialogVisible: boolean, + currentError: number, +} + + +export default class VoteSelect extends React.PureComponent { + + state = { + selectedTeam: "none", + voteDialogVisible: false, + errorDialogVisible: false, + currentError: 0, + }; + + onVoteSelectionChange = (team: string) => this.setState({selectedTeam: team}); + + voteKeyExtractor = (item: Object) => item.id.toString(); + + voteRenderItem = ({item}: Object) => ; + + showVoteDialog = () => this.setState({voteDialogVisible: true}); + + onVoteDialogDismiss = () => this.setState({voteDialogVisible: false,}); + + onVoteDialogAccept = async () => { + return new Promise((resolve, reject) => { + ConnectionManager.getInstance().authenticatedRequest( + "elections/vote", + ["vote"], + [parseInt(this.state.selectedTeam)]) + .then(() => { + this.onVoteDialogDismiss(); + this.props.onVoteSuccess(); + resolve(); + }) + .catch((error: number) => { + this.onVoteDialogDismiss(); + this.showErrorDialog(error); + resolve(); + }); + }); + }; + + showErrorDialog = (error: number) => this.setState({ + errorDialogVisible: true, + currentError: error, + }); + + onErrorDialogDismiss = () => { + this.setState({errorDialogVisible: false}); + this.props.onVoteError(); + }; + + render() { + return ( + + + } + /> + + + {/*$FlowFixMe*/} + + + + + + + + + + + ); + } +} + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent' + }, +}); diff --git a/src/components/Amicale/Vote/VoteTease.js b/src/components/Amicale/Vote/VoteTease.js new file mode 100644 index 0000000..b648031 --- /dev/null +++ b/src/components/Amicale/Vote/VoteTease.js @@ -0,0 +1,45 @@ +// @flow + +import * as React from 'react'; +import {Avatar, Card, Paragraph} from "react-native-paper"; +import {StyleSheet} from "react-native"; + +type Props = { + startDate: string, +} + +export default class VoteTease extends React.Component { + + shouldComponentUpdate() { + return false; + } + + render() { + return ( + + } + /> + + + VOTE STARTS + AT {this.props.startDate} + + + + ); + } +} + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent' + }, +}); diff --git a/src/components/Amicale/Vote/VoteTitle.js b/src/components/Amicale/Vote/VoteTitle.js new file mode 100644 index 0000000..d81b333 --- /dev/null +++ b/src/components/Amicale/Vote/VoteTitle.js @@ -0,0 +1,54 @@ +// @flow + +import * as React from 'react'; +import {Avatar, Card, Paragraph} from "react-native-paper"; +import {StyleSheet} from "react-native"; + +const ICON_AMICALE = require('../../../../assets/amicale.png'); + +type Props = {} + +export default class VoteTitle extends React.Component { + + shouldComponentUpdate() { + return false; + } + + render() { + return ( + + } + /> + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rhoncus porttitor + suscipit. Quisque hendrerit, quam id vestibulum vestibulum, lorem nisi hendrerit nisi, a + eleifend sapien diam ut elit. Curabitur sit amet vulputate lectus. Donec semper cursus sapien + vel finibus. + + + Sed et venenatis turpis. Fusce malesuada magna urna, sed vehicula sem luctus in. Vivamus + faucibus vel eros a ultricies. In sed laoreet ante, luctus mattis tellus. Etiam vitae ipsum + sagittis, consequat purus sed, blandit risus. + + + + ); + } +} + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent' + }, +}); diff --git a/src/components/Amicale/Vote/VoteWait.js b/src/components/Amicale/Vote/VoteWait.js new file mode 100644 index 0000000..e098029 --- /dev/null +++ b/src/components/Amicale/Vote/VoteWait.js @@ -0,0 +1,73 @@ +// @flow + +import * as React from 'react'; +import {ActivityIndicator, Card, Paragraph, withTheme} from "react-native-paper"; +import {StyleSheet} from "react-native"; + +type Props = { + startDate: string | null, + justVoted: boolean, + hasVoted: boolean, + isVoteRunning: boolean, +} + +class VoteWait extends React.Component { + + colors: Object; + + constructor(props) { + super(props); + this.colors = props.theme.colors; + } + + shouldComponentUpdate() { + return false; + } + + render() { + return ( + + } + /> + + { + this.props.justVoted + ? + VOTE SUBMITTED. THX FOR YOUR PARTICIPATION + + : null + } + { + this.props.hasVoted + ? + THX FOR THE VOTE + + : null + } + { + this.props.startDate !== null + ? + RESULTS AVAILABLE + AT {this.props.startDate} + + : RESULTS AVAILABLE SHORTLY + } + + + ); + } +} + +const styles = StyleSheet.create({ + card: { + margin: 10, + }, + icon: { + backgroundColor: 'transparent' + }, +}); + +export default withTheme(VoteWait); diff --git a/src/managers/ConnectionManager.js b/src/managers/ConnectionManager.js index e45a375..f36183e 100644 --- a/src/managers/ConnectionManager.js +++ b/src/managers/ConnectionManager.js @@ -190,11 +190,11 @@ export default class ConnectionManager { return data; } - async authenticatedRequest(path: string, keys: Array, values: Array) { + async authenticatedRequest(path: string, keys: Array|null, values: Array|null) { return new Promise((resolve, reject) => { if (this.getToken() !== null) { let data = {}; - if (keys !== undefined && values !== undefined && keys.length === values.length) + if (keys !== null && values !== null && keys.length === values.length) data = this.generatePostArguments(keys, values); console.log(data); fetch(API_ENDPOINT + path, { diff --git a/src/screens/Amicale/VoteScreen.js b/src/screens/Amicale/VoteScreen.js index eee9cbb..406b7f9 100644 --- a/src/screens/Amicale/VoteScreen.js +++ b/src/screens/Amicale/VoteScreen.js @@ -1,32 +1,20 @@ // @flow import * as React from 'react'; -import {FlatList, StyleSheet, View} from "react-native"; -import { - ActivityIndicator, - Avatar, - Button, - Card, - List, - Paragraph, - ProgressBar, - RadioButton, - Subheading, - withTheme -} from 'react-native-paper'; +import {FlatList, View} from "react-native"; import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen"; import {getTimeOnlyString, stringToDate} from "../../utils/Planning"; -import LoadingConfirmDialog from "../../components/Dialog/LoadingConfirmDialog"; -import ConnectionManager from "../../managers/ConnectionManager"; -import ErrorDialog from "../../components/Dialog/ErrorDialog"; - -const ICON_AMICALE = require('../../../assets/amicale.png'); +import VoteTitle from "../../components/Amicale/Vote/VoteTitle"; +import VoteTease from "../../components/Amicale/Vote/VoteTease"; +import VoteSelect from "../../components/Amicale/Vote/VoteSelect"; +import VoteResults from "../../components/Amicale/Vote/VoteResults"; +import VoteWait from "../../components/Amicale/Vote/VoteWait"; const FAKE_DATE = { "date_begin": "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", + "date_result_end": "2020-04-07 22:50", }; const FAKE_DATE2 = { @@ -65,31 +53,18 @@ const FAKE_TEAMS2 = { ], }; -type Props = { - navigation: Object, - theme: Object, -} +type Props = {} type State = { - selectedTeam: string, hasVoted: boolean, - voteDialogVisible: boolean, - errorDialogVisible: boolean, - currentError: number, } -class VoteScreen extends React.Component { +export default class VoteScreen extends React.Component { state = { - selectedTeam: "none", - voteDialogVisible: false, - errorDialogVisible: false, - currentError: 0, hasVoted: false, }; - colors: Object; - teams: Array; hasVoted: boolean; datesString: Object; @@ -98,13 +73,11 @@ class VoteScreen extends React.Component { today: Date; mainFlatListData: Array; - totalVotes: number; authRef: Object; - constructor(props) { - super(props); - this.colors = props.theme.colors; + constructor() { + super(); this.hasVoted = false; this.today = new Date(); this.authRef = React.createRef(); @@ -125,10 +98,11 @@ class VoteScreen extends React.Component { }; } - getDateString(date: Date, dateString: string) { - if (this.today.getDate() === date.getDate()) - return getTimeOnlyString(dateString); - else + getDateString(date: Date, dateString: string): string { + if (this.today.getDate() === date.getDate()) { + const str = getTimeOnlyString(dateString); + return str !== null ? str : ""; + } else return dateString; } @@ -154,7 +128,7 @@ class VoteScreen extends React.Component { mainRenderItem = ({item}: Object) => { if (item.key === 'info') - return this.getTitleCard(); + return ; else if (item.key === 'main' && this.isVoteAvailable()) return this.getContent(); else @@ -176,64 +150,13 @@ class VoteScreen extends React.Component { {/*$FlowFixMe*/} - - ); }; - showVoteDialog = () => this.setState({voteDialogVisible: true}); - - onVoteDialogDismiss = (voteStatus: boolean) => { - voteStatus = voteStatus === undefined ? false : voteStatus; - this.setState({ - voteDialogVisible: false, - hasVoted: voteStatus, - }) - }; - - onVoteDialogAccept = async () => { - return new Promise((resolve, reject) => { - ConnectionManager.getInstance().authenticatedRequest( - "elections/vote", - ["vote"], - [parseInt(this.state.selectedTeam)]) - .then(() => { - this.onVoteDialogDismiss(true); - resolve(); - }) - .catch((error: number) => { - this.onVoteDialogDismiss(false); - this.showErrorDialog(error); - resolve(); - }); - }); - }; - - showErrorDialog = (error: number) => this.setState({ - errorDialogVisible: true, - currentError: error, - }); - - onErrorDialogDismiss = () => { - this.setState({errorDialogVisible: false}); - this.reloadData(); - }; - getContent() { if (!this.isVoteStarted()) return this.getTeaseVoteCard(); @@ -247,218 +170,39 @@ class VoteScreen extends React.Component { return null; } - getTitleCard() { - return ( - - } - /> - - - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus rhoncus porttitor - suscipit. Quisque hendrerit, quam id vestibulum vestibulum, lorem nisi hendrerit nisi, a - eleifend sapien diam ut elit. Curabitur sit amet vulputate lectus. Donec semper cursus sapien - vel finibus. - - - Sed et venenatis turpis. Fusce malesuada magna urna, sed vehicula sem luctus in. Vivamus - faucibus vel eros a ultricies. In sed laoreet ante, luctus mattis tellus. Etiam vitae ipsum - sagittis, consequat purus sed, blandit risus. - - - - ); - } - - onVoteSelectionChange = (team: string) => { - this.setState({selectedTeam: team}) - }; - - onVotePress = () => { - this.showVoteDialog(); - }; - - voteKeyExtractor = (item: Object) => item.id.toString(); - - voteRenderItem = ({item}: Object) => ; + onVoteSuccess = () => this.setState({hasVoted: true}); /** * The user has not voted yet, and the votes are open */ getVoteCard() { - return ( - - } - /> - - - {/*$FlowFixMe*/} - - - - - - - - ); - } - - sortByVotes = (a: Object, b: Object) => b.votes - a.votes; - - getTotalVotes() { - let count = 0; - for (let i = 0; i < this.teams.length; i++) { - count += this.teams[i].votes; - } - return count; - } - - getWinnerId() { - return this.teams[0].id; + return ; } /** * Votes have ended, results can be displayed */ getVoteResultCard() { - this.totalVotes = this.getTotalVotes(); - this.teams.sort(this.sortByVotes); - return ( - - } - /> - - TOTAL VOTES : {this.totalVotes} - {/*$FlowFixMe*/} - - - - ); + return ; } - resultRenderItem = ({item}: Object) => { - const isWinner = this.getWinnerId() === item.id; - return ( - - isWinner - ? - : null} - titleStyle={{ - color: isWinner - ? this.colors.primary - : this.colors.text - }} - style={{padding: 0}} - /> - - - ); - }; - /** * Vote will open shortly */ getTeaseVoteCard() { - return ( - - } - /> - - - VOTE STARTS - AT {this.getDateString(this.dates.date_begin, this.datesString.date_begin)} - - - - ); + return ; } /** - * Votes have ended waiting for results + * Votes have ended, or user has voted waiting for results */ getWaitVoteCard() { - return ( - - } - /> - - { - this.state.hasVoted - ? - VOTE SUBMITTED. THX FOR YOUR PARTICIPATION - - : null - } - { - this.hasVoted - ? - THX FOR THE VOTE - - : null - } - { - this.dates.date_result_begin !== null - ? - RESULTS AVAILABLE - AT {this.getDateString(this.dates.date_result_begin, this.datesString.date_result_begin)} - - : RESULTS AVAILABLE SHORTLY - } - - - ); + let startDate = null; + if (this.dates.date_result_begin !== null) + startDate = this.getDateString(this.dates.date_result_begin, this.datesString.date_result_begin); + return ; } render() { @@ -481,14 +225,3 @@ class VoteScreen extends React.Component { ); } } - -const styles = StyleSheet.create({ - card: { - margin: 10, - }, - icon: { - backgroundColor: 'transparent' - }, -}); - -export default withTheme(VoteScreen);