application-amicale/src/screens/Amicale/VoteScreen.js

467 lines
14 KiB
JavaScript

// @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 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');
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",
};
const FAKE_DATE2 = {
"date_begin": null,
"date_end": null,
"date_result_begin": null,
"date_result_end": null,
};
const FAKE_TEAMS = {
has_voted: false,
teams: [
{
id: 1,
name: "TEST TEAM1",
},
{
id: 2,
name: "TEST TEAM2",
},
],
};
const FAKE_TEAMS2 = {
has_voted: false,
teams: [
{
id: 1,
name: "TEST TEAM1",
votes: 1,
},
{
id: 2,
name: "TEST TEAM2",
votes: 9,
},
],
};
type Props = {
navigation: Object,
theme: Object,
}
type State = {
selectedTeam: string,
voteDialogVisible: boolean,
errorDialogVisible: boolean,
currentError: number,
}
class VoteScreen extends React.Component<Props, State> {
state = {
selectedTeam: "none",
voteDialogVisible: false,
errorDialogVisible: false,
currentError: 0,
};
colors: Object;
teams: Array<Object>;
hasVoted: boolean;
datesString: Object;
dates: Object;
today: Date;
mainFlatListData: Array<Object>;
totalVotes: number;
constructor(props) {
super(props);
this.colors = props.theme.colors;
this.hasVoted = false;
this.today = new Date();
this.mainFlatListData = [
{key: 'main'},
{key: 'info'},
]
}
mainRenderItem = ({item}: Object) => {
if (item.key === 'info')
return this.getTitleCard();
else if (item.key === 'main' && this.isVoteAvailable())
return this.getContent();
else
return null;
};
getScreen = (data: Array<Object>) => {
data[0] = FAKE_TEAMS2;
data[1] = FAKE_DATE;
if (data[0] !== null) {
this.teams = data[0].teams;
this.hasVoted = data[0].has_voted;
}
this.datesString = data[1];
this.generateDateObject();
return (
<View>
{/*$FlowFixMe*/}
<FlatList
data={this.mainFlatListData}
extraData={this.state.selectedTeam}
renderItem={this.mainRenderItem}
/>
<LoadingConfirmDialog
visible={this.state.voteDialogVisible}
onDismiss={this.onVoteDialogDismiss}
onAccept={this.onVoteDialogAccept}
title={"VOTE?"}
titleLoading={"SENDING VOTE..."}
message={"SURE?"}
/>
<ErrorDialog
visible={this.state.errorDialogVisible}
onDismiss={this.onErrorDialogDismiss}
errorCode={this.state.currentError}
/>
</View>
);
};
onVoteDialogDismiss = () => this.setState({voteDialogVisible: false});
onErrorDialogDismiss = () => this.setState({errorDialogVisible: false});
showVoteDialog = () => this.setState({voteDialogVisible: true});
showErrorDialog = (error: number) => this.setState({
errorDialogVisible: true,
currentError: error,
});
onVoteDialogAccept = async () => {
return new Promise((resolve, reject) => {
ConnectionManager.getInstance().authenticatedRequest(
"elections/vote",
["vote"],
[parseInt(this.state.selectedTeam)])
.then(() => {
this.onVoteDialogDismiss();
resolve();
})
.catch((error: number) => {
this.onVoteDialogDismiss();
this.showErrorDialog(error);
resolve();
});
});
};
generateDateObject() {
this.dates = {
date_begin: stringToDate(this.datesString.date_begin),
date_end: stringToDate(this.datesString.date_end),
date_result_begin: stringToDate(this.datesString.date_result_begin),
date_result_end: stringToDate(this.datesString.date_result_end),
};
}
isVoteAvailable() {
return this.dates.date_begin !== null;
}
isVoteRunning() {
return this.today > this.dates.date_begin && this.today < this.dates.date_end;
}
isVoteStarted() {
return this.today > this.dates.date_begin;
}
isResultRunning() {
return this.today > this.dates.date_result_begin && this.today < this.dates.date_result_end;
}
isResultStarted() {
return this.today > this.dates.date_result_begin;
}
getContent() {
if (!this.isVoteStarted())
return this.getTeaseVoteCard();
else if (this.isVoteRunning() && !this.hasVoted)
return this.getVoteCard();
else if (!this.isResultStarted())
return this.getWaitVoteCard();
else if (this.isResultRunning())
return this.getVoteResultCard();
else
return null;
}
getTitleCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE"}
subtitle={"WHY"}
left={(props) => <Avatar.Image
{...props}
source={ICON_AMICALE}
style={styles.icon}
/>}
/>
<Card.Content>
<Paragraph>
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.
</Paragraph>
<Paragraph>
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.
</Paragraph>
</Card.Content>
</Card>
);
}
onVoteSelectionChange = (team: string) => {
this.setState({selectedTeam: team})
};
onVotePress = () => {
this.showVoteDialog();
};
voteKeyExtractor = (item: Object) => item.id.toString();
voteRenderItem = ({item}: Object) => <RadioButton.Item label={item.name} value={item.id.toString()}/>;
/**
* The user has not voted yet, and the votes are open
*/
getVoteCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE OPEN"}
subtitle={"VOTE NOW"}
left={(props) => <Avatar.Icon
{...props}
icon={"alert-decagram"}
/>}
/>
<Card.Content>
<RadioButton.Group
onValueChange={this.onVoteSelectionChange}
value={this.state.selectedTeam}
>
{/*$FlowFixMe*/}
<FlatList
data={this.teams}
keyExtractor={this.voteKeyExtractor}
extraData={this.state.selectedTeam}
renderItem={this.voteRenderItem}
/>
</RadioButton.Group>
</Card.Content>
<Card.Actions>
<Button
icon="send"
mode="contained"
onPress={this.onVotePress}
style={{marginLeft: 'auto'}}
disabled={this.state.selectedTeam === "none"}
>
SEND VOTE
</Button>
</Card.Actions>
</Card>
);
}
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;
}
/**
* Votes have ended, results can be displayed
*/
getVoteResultCard() {
this.totalVotes = this.getTotalVotes();
this.teams.sort(this.sortByVotes);
return (
<Card style={styles.card}>
<Card.Title
title={"RESULTS"}
subtitle={"AVAILABLE UNTIL " + this.getDateString(this.dates.date_result_end, this.datesString.date_result_end)}
left={(props) => <Avatar.Icon
{...props}
icon={"podium-gold"}
/>}
/>
<Card.Content>
<Subheading>TOTAL VOTES : {this.totalVotes}</Subheading>
{/*$FlowFixMe*/}
<FlatList
data={this.teams}
keyExtractor={this.voteKeyExtractor}
renderItem={this.resultRenderItem}
/>
</Card.Content>
</Card>
);
}
resultRenderItem = ({item}: Object) => {
const isWinner = this.getWinnerId() === item.id;
return (
<Card style={{
marginTop: 10,
elevation: isWinner ? 5 : 3,
}}>
<List.Item
title={item.name}
description={item.votes + " VOTES"}
left={props => isWinner
? <List.Icon {...props} icon="trophy" color={this.colors.primary}/>
: null}
titleStyle={{
color: isWinner
? this.colors.primary
: this.colors.text
}}
style={{padding: 0}}
/>
<ProgressBar progress={item.votes / this.totalVotes} color={this.colors.primary}/>
</Card>
);
};
/**
* Vote will open shortly
*/
getTeaseVoteCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTE INCOMING"}
subtitle={"GET READY"}
left={props => <Avatar.Icon
{...props}
icon="vote"/>}
/>
<Card.Content>
<Paragraph>
VOTE STARTS
AT {this.getDateString(this.dates.date_begin, this.datesString.date_begin)}
</Paragraph>
</Card.Content>
</Card>
);
}
/**
* Votes have ended waiting for results
*/
getWaitVoteCard() {
return (
<Card style={styles.card}>
<Card.Title
title={"VOTES HAVE ENDED"}
subtitle={"WAITING FOR RESULTS"}
left={(props) => <ActivityIndicator {...props}/>}
/>
<Card.Content>
{
this.hasVoted
? <Paragraph>THX FOR THE VOTE</Paragraph>
: null
}
{
this.dates.date_result_begin !== null
? <Paragraph>
RESULTS AVAILABLE
AT {this.getDateString(this.dates.date_result_begin, this.datesString.date_result_begin)}
</Paragraph>
: <Paragraph>RESULTS AVAILABLE SHORTLY</Paragraph>
}
</Card.Content>
</Card>
);
}
getDateString(date: Date, dateString: string) {
if (this.today.getDate() === date.getDate())
return getTimeOnlyString(dateString);
else
return dateString;
}
render() {
return (
<AuthenticatedScreen
{...this.props}
links={[
{
link: 'elections/teams',
mandatory: false,
},
{
link: 'elections/datesString',
mandatory: false,
},
]}
renderFunction={this.getScreen}
/>
);
}
}
const styles = StyleSheet.create({
card: {
margin: 10,
},
icon: {
backgroundColor: 'transparent'
},
});
export default withTheme(VoteScreen);