Compare commits

..

2 commits

Author SHA1 Message Date
0b85b1630c Polished vote display 2020-04-06 23:38:35 +02:00
98b1d267ec Added basic vote display 2020-04-06 19:49:32 +02:00
3 changed files with 212 additions and 35 deletions

View file

@ -36,6 +36,7 @@ class AuthenticatedScreen extends React.Component<Props, State> {
this.connectionManager = ConnectionManager.getInstance(); this.connectionManager = ConnectionManager.getInstance();
this.props.navigation.addListener('focus', this.onScreenFocus.bind(this)); this.props.navigation.addListener('focus', this.onScreenFocus.bind(this));
this.data = new Array(this.props.links.length); this.data = new Array(this.props.links.length);
this.fetchData(); // TODO remove in prod (only use for fast refresh)
} }
onScreenFocus() { onScreenFocus() {

View file

@ -1,10 +1,21 @@
// @flow // @flow
import * as React from 'react'; import * as React from 'react';
import {ScrollView, StyleSheet} from "react-native"; import {FlatList, StyleSheet} from "react-native";
import {Avatar, Card, Paragraph, 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,36 +43,75 @@ 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,
}, },
], ],
}; };
type State = {} type State = {
selectedTeam: string,
}
class VoteScreen extends React.Component<Props, State> { class VoteScreen extends React.Component<Props, State> {
state = {}; state = {
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;
today: Date; today: Date;
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 = [
{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>) => { 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) {
@ -72,16 +122,13 @@ class VoteScreen extends React.Component<Props, State> {
this.generateDateObject(); this.generateDateObject();
console.log(this.teams); console.log(this.teams);
console.log(this.datesString); console.log(this.datesString);
console.log(this.dates);
return ( return (
<ScrollView> //$FlowFixMe
{ <FlatList
this.isVoteAvailable() data={this.mainFlatListData}
? this.getContent() extraData={this.state.selectedTeam}
: null renderItem={this.mainRenderItem}
} />
{this.getTitleCard()}
</ScrollView>
); );
}; };
@ -156,6 +203,18 @@ class VoteScreen extends React.Component<Props, State> {
); );
} }
onVoteSelectionChange = (team: string) => {
this.setState({selectedTeam: team})
};
onVotePress = () => {
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
*/ */
@ -163,35 +222,110 @@ class VoteScreen extends React.Component<Props, State> {
return ( return (
<Card style={styles.card}> <Card style={styles.card}>
<Card.Title <Card.Title
title={"getVoteCard"} title={"VOTE OPEN"}
subtitle={"getVoteCard"} subtitle={"VOTE NOW"}
left={(props) => <Avatar.Icon
{...props}
icon={"alert-decagram"}
/>}
/> />
<Card.Content> <Card.Content>
<Paragraph>TEAM1</Paragraph> <RadioButton.Group
<Paragraph>TEAM2</Paragraph> 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.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> </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 * 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
*/ */
@ -199,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

View file

@ -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