forked from vergnet/application-amicale
Polished vote display
This commit is contained in:
parent
98b1d267ec
commit
0b85b1630c
2 changed files with 149 additions and 25 deletions
|
@ -2,9 +2,20 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {FlatList, StyleSheet} from "react-native";
|
import {FlatList, StyleSheet} from "react-native";
|
||||||
import {Avatar, Button, Card, Paragraph, RadioButton, withTheme} from 'react-native-paper';
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Avatar,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
List,
|
||||||
|
Paragraph,
|
||||||
|
ProgressBar,
|
||||||
|
RadioButton,
|
||||||
|
Subheading,
|
||||||
|
withTheme
|
||||||
|
} from 'react-native-paper';
|
||||||
import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
|
import AuthenticatedScreen from "../../components/Amicale/AuthenticatedScreen";
|
||||||
import {stringToDate} from "../../utils/Planning";
|
import {getTimeOnlyString, stringToDate} from "../../utils/Planning";
|
||||||
|
|
||||||
const ICON_AMICALE = require('../../../assets/amicale.png');
|
const ICON_AMICALE = require('../../../assets/amicale.png');
|
||||||
|
|
||||||
|
@ -14,10 +25,10 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const FAKE_DATE = {
|
const FAKE_DATE = {
|
||||||
"date_begin": "2020-04-06 13:00",
|
"date_begin": "2020-04-06 21:50",
|
||||||
"date_end": "2020-04-06 20:00",
|
"date_end": "2020-04-06 21:50",
|
||||||
"date_result_begin": "2020-04-06 20:15",
|
"date_result_begin": "2020-04-06 21:50",
|
||||||
"date_result_end": "2020-04-07 12:00",
|
"date_result_end": "2020-04-06 21:50",
|
||||||
};
|
};
|
||||||
|
|
||||||
const FAKE_DATE2 = {
|
const FAKE_DATE2 = {
|
||||||
|
@ -32,7 +43,26 @@ const FAKE_TEAMS = {
|
||||||
teams: [
|
teams: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "TEST TEAM",
|
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,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
@ -44,12 +74,12 @@ type State = {
|
||||||
class VoteScreen extends React.Component<Props, State> {
|
class VoteScreen extends React.Component<Props, State> {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
selectedTeam: "0",
|
selectedTeam: "none",
|
||||||
};
|
};
|
||||||
|
|
||||||
colors: Object;
|
colors: Object;
|
||||||
|
|
||||||
teams: Array<Object> | null;
|
teams: Array<Object>;
|
||||||
hasVoted: boolean;
|
hasVoted: boolean;
|
||||||
datesString: Object;
|
datesString: Object;
|
||||||
dates: Object;
|
dates: Object;
|
||||||
|
@ -57,12 +87,12 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
today: Date;
|
today: Date;
|
||||||
|
|
||||||
mainFlatListData: Array<Object>;
|
mainFlatListData: Array<Object>;
|
||||||
|
totalVotes: number;
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.colors = props.theme.colors;
|
this.colors = props.theme.colors;
|
||||||
this.hasVoted = false;
|
this.hasVoted = false;
|
||||||
this.teams = null;
|
|
||||||
this.today = new Date();
|
this.today = new Date();
|
||||||
|
|
||||||
this.mainFlatListData = [
|
this.mainFlatListData = [
|
||||||
|
@ -81,7 +111,7 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
getScreen = (data: Array<Object>) => {
|
getScreen = (data: Array<Object>) => {
|
||||||
data[0] = FAKE_TEAMS;
|
data[0] = FAKE_TEAMS2;
|
||||||
data[1] = FAKE_DATE;
|
data[1] = FAKE_DATE;
|
||||||
|
|
||||||
if (data[0] !== null) {
|
if (data[0] !== null) {
|
||||||
|
@ -93,6 +123,7 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
console.log(this.teams);
|
console.log(this.teams);
|
||||||
console.log(this.datesString);
|
console.log(this.datesString);
|
||||||
return (
|
return (
|
||||||
|
//$FlowFixMe
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.mainFlatListData}
|
data={this.mainFlatListData}
|
||||||
extraData={this.state.selectedTeam}
|
extraData={this.state.selectedTeam}
|
||||||
|
@ -180,6 +211,10 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
console.log("vote sent");
|
console.log("vote sent");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
* The user has not voted yet, and the votes are open
|
||||||
*/
|
*/
|
||||||
|
@ -199,6 +234,7 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
onValueChange={this.onVoteSelectionChange}
|
onValueChange={this.onVoteSelectionChange}
|
||||||
value={this.state.selectedTeam}
|
value={this.state.selectedTeam}
|
||||||
>
|
>
|
||||||
|
{/*$FlowFixMe*/}
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.teams}
|
data={this.teams}
|
||||||
keyExtractor={this.voteKeyExtractor}
|
keyExtractor={this.voteKeyExtractor}
|
||||||
|
@ -212,7 +248,9 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
icon="send"
|
icon="send"
|
||||||
mode="contained"
|
mode="contained"
|
||||||
onPress={this.onVotePress}
|
onPress={this.onVotePress}
|
||||||
style={{marginLeft: 'auto'}}>
|
style={{marginLeft: 'auto'}}
|
||||||
|
disabled={this.state.selectedTeam === "none"}
|
||||||
|
>
|
||||||
SEND VOTE
|
SEND VOTE
|
||||||
</Button>
|
</Button>
|
||||||
</Card.Actions>
|
</Card.Actions>
|
||||||
|
@ -220,30 +258,74 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
voteKeyExtractor = (item: Object) => item.id.toString();
|
sortByVotes = (a: Object, b: Object) => b.votes - a.votes;
|
||||||
|
|
||||||
voteRenderItem = ({item}: Object) => {
|
getTotalVotes() {
|
||||||
return <RadioButton.Item label={item.name} value={item.id.toString()}/>
|
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
|
* Votes have ended, results can be displayed
|
||||||
*/
|
*/
|
||||||
getVoteResultCard() {
|
getVoteResultCard() {
|
||||||
|
this.totalVotes = this.getTotalVotes();
|
||||||
|
this.teams.sort(this.sortByVotes);
|
||||||
return (
|
return (
|
||||||
<Card style={styles.card}>
|
<Card style={styles.card}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={"getVoteResultCard"}
|
title={"RESULTS"}
|
||||||
subtitle={"getVoteResultCard"}
|
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>
|
<Card.Content>
|
||||||
<Paragraph>TEAM1</Paragraph>
|
<Subheading>TOTAL VOTES : {this.totalVotes}</Subheading>
|
||||||
<Paragraph>TEAM2</Paragraph>
|
{/*$FlowFixMe*/}
|
||||||
|
<FlatList
|
||||||
|
data={this.teams}
|
||||||
|
keyExtractor={this.voteKeyExtractor}
|
||||||
|
renderItem={this.resultRenderItem}
|
||||||
|
/>
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card>
|
</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
|
* Vote will open shortly
|
||||||
*/
|
*/
|
||||||
|
@ -251,31 +333,59 @@ class VoteScreen extends React.Component<Props, State> {
|
||||||
return (
|
return (
|
||||||
<Card style={styles.card}>
|
<Card style={styles.card}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={"getTeaseVoteCard"}
|
title={"VOTE INCOMING"}
|
||||||
subtitle={"getTeaseVoteCard"}
|
subtitle={"GET READY"}
|
||||||
|
left={props => <Avatar.Icon
|
||||||
|
{...props}
|
||||||
|
icon="vote"/>}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
<Paragraph>
|
||||||
|
VOTE STARTS
|
||||||
|
AT {this.getDateString(this.dates.date_begin, this.datesString.date_begin)}
|
||||||
|
</Paragraph>
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User has voted, waiting for results
|
* Votes have ended waiting for results
|
||||||
*/
|
*/
|
||||||
getWaitVoteCard() {
|
getWaitVoteCard() {
|
||||||
return (
|
return (
|
||||||
<Card style={styles.card}>
|
<Card style={styles.card}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={"getWaitVoteCard"}
|
title={"VOTES HAVE ENDED"}
|
||||||
subtitle={"getWaitVoteCard"}
|
subtitle={"WAITING FOR RESULTS"}
|
||||||
|
left={(props) => <ActivityIndicator {...props}/>}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<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.Content>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDateString(date: Date, dateString: string) {
|
||||||
|
if (this.today.getDate() === date.getDate())
|
||||||
|
return getTimeOnlyString(dateString);
|
||||||
|
else
|
||||||
|
return dateString;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<AuthenticatedScreen
|
<AuthenticatedScreen
|
||||||
|
|
|
@ -55,6 +55,20 @@ export function getDateOnlyString(dateString: string): string | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets only the time part of the given event date string in the format
|
||||||
|
* YYYY-MM-DD HH:MM
|
||||||
|
*
|
||||||
|
* @param dateString The string to get the date from
|
||||||
|
* @return {string|null} Time in format HH:MM or null if given string is invalid
|
||||||
|
*/
|
||||||
|
export function getTimeOnlyString(dateString: string): string | null {
|
||||||
|
if (isEventDateStringFormatValid(dateString))
|
||||||
|
return dateString.split(" ")[1];
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given date string is in the format
|
* Checks if the given date string is in the format
|
||||||
* YYYY-MM-DD HH:MM
|
* YYYY-MM-DD HH:MM
|
||||||
|
|
Loading…
Reference in a new issue