mirror of https://gitlab.com/ecentrics/concordia
Apostolos Fanakis
4 years ago
9 changed files with 387 additions and 9 deletions
@ -0,0 +1,82 @@ |
|||
import React, { useMemo } from 'react'; |
|||
import Chart from 'react-apexcharts'; |
|||
import { Grid, Header } from 'semantic-ui-react'; |
|||
import PropTypes from 'prop-types'; |
|||
import { useTranslation } from 'react-i18next'; |
|||
import { CASTED_OPTION_COLOR, DEFAULT_OPTION_COLOR } from '../../../constants/polls/PollGraph'; |
|||
|
|||
const PollGraph = (props) => { |
|||
const { |
|||
pollOptions, voteCounts, hasUserVoted, userVoteHash, |
|||
} = props; |
|||
const { t } = useTranslation(); |
|||
|
|||
const chartOptions = useMemo(() => ({ |
|||
chart: { |
|||
id: 'topic-poll', |
|||
}, |
|||
plotOptions: { |
|||
bar: { |
|||
horizontal: true, |
|||
}, |
|||
}, |
|||
colors: [ |
|||
(value) => { |
|||
if (hasUserVoted && pollOptions[value.dataPointIndex].hash === userVoteHash) { |
|||
return CASTED_OPTION_COLOR; |
|||
} |
|||
return DEFAULT_OPTION_COLOR; |
|||
}, |
|||
], |
|||
xaxis: { |
|||
categories: pollOptions.map((pollOption) => pollOption.label), |
|||
}, |
|||
}), [hasUserVoted, pollOptions, userVoteHash]); |
|||
|
|||
const chartSeries = useMemo(() => [{ |
|||
name: 'votes', |
|||
data: voteCounts, |
|||
}], [voteCounts]); |
|||
|
|||
return ( |
|||
<Grid columns="equal"> |
|||
<Grid.Row> |
|||
<Grid.Column /> |
|||
<Grid.Column width={8}> |
|||
<Chart |
|||
options={chartOptions} |
|||
series={chartSeries} |
|||
type="bar" |
|||
/> |
|||
</Grid.Column> |
|||
<Grid.Column /> |
|||
</Grid.Row> |
|||
<Grid.Row> |
|||
<Grid.Column textAlign="center"> |
|||
<Header as="h4"> |
|||
{t('topic.poll.tab.results.votes.count', { |
|||
totalVotes: voteCounts.reduce((accumulator, voteCount) => accumulator + voteCount, 0), |
|||
})} |
|||
</Header> |
|||
</Grid.Column> |
|||
</Grid.Row> |
|||
</Grid> |
|||
); |
|||
}; |
|||
|
|||
PollGraph.defaultProps = { |
|||
hasUserVoted: false, |
|||
userVoteHash: '', |
|||
}; |
|||
|
|||
PollGraph.propTypes = { |
|||
pollOptions: PropTypes.arrayOf(PropTypes.exact({ |
|||
label: PropTypes.string, |
|||
hash: PropTypes.string, |
|||
})).isRequired, |
|||
voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired, |
|||
hasUserVoted: PropTypes.bool, |
|||
userVoteHash: PropTypes.string, |
|||
}; |
|||
|
|||
export default PollGraph; |
@ -0,0 +1,62 @@ |
|||
import React, { useState } from 'react'; |
|||
import PropTypes from 'prop-types'; |
|||
import { Form } from 'semantic-ui-react'; |
|||
import { useTranslation } from 'react-i18next'; |
|||
|
|||
const PollVote = (props) => { |
|||
const { |
|||
pollOptions, enableVoteChanges, hasUserVoted, userVoteHash, |
|||
} = props; |
|||
const [selectedOptionHash, setSelectedOptionHash] = useState(userVoteHash); |
|||
const { t } = useTranslation(); |
|||
|
|||
const onOptionSelected = (e, { value }) => { |
|||
setSelectedOptionHash(value); |
|||
}; |
|||
|
|||
const onCastVote = () => { |
|||
console.log('vote'); |
|||
// TODO |
|||
// TODO: callback for immediate poll data refresh on vote? |
|||
}; |
|||
|
|||
return ( |
|||
<Form onSubmit={onCastVote}> |
|||
<Form.Group grouped> |
|||
<label htmlFor="poll">{t('topic.poll.tab.vote.form.radio.label')}</label> |
|||
{pollOptions.map((pollOption) => ( |
|||
<Form.Radio |
|||
key={pollOption.hash} |
|||
label={pollOption.label} |
|||
value={pollOption.hash} |
|||
checked={pollOption.hash === selectedOptionHash} |
|||
disabled={hasUserVoted && !enableVoteChanges && pollOption.hash !== selectedOptionHash} |
|||
onChange={onOptionSelected} |
|||
/> |
|||
))} |
|||
</Form.Group> |
|||
<Form.Button |
|||
type="submit" |
|||
disabled={(hasUserVoted && !enableVoteChanges) || (selectedOptionHash === userVoteHash)} |
|||
> |
|||
{t('topic.poll.tab.vote.form.button.submit')} |
|||
</Form.Button> |
|||
</Form> |
|||
); |
|||
}; |
|||
|
|||
PollVote.defaultProps = { |
|||
userVoteHash: '', |
|||
}; |
|||
|
|||
PollVote.propTypes = { |
|||
pollOptions: PropTypes.arrayOf(PropTypes.exact({ |
|||
label: PropTypes.string, |
|||
hash: PropTypes.string, |
|||
})).isRequired, |
|||
enableVoteChanges: PropTypes.bool.isRequired, |
|||
hasUserVoted: PropTypes.bool.isRequired, |
|||
userVoteHash: PropTypes.string, |
|||
}; |
|||
|
|||
export default PollVote; |
@ -0,0 +1,99 @@ |
|||
import React, { useMemo, useState } from 'react'; |
|||
import { useSelector } from 'react-redux'; |
|||
import { VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; |
|||
import { |
|||
Container, Header, Icon, Tab, |
|||
} from 'semantic-ui-react'; |
|||
import { useTranslation } from 'react-i18next'; |
|||
import { drizzle } from '../../redux/store'; |
|||
import PollGraph from './PollGraph'; |
|||
import CustomLoadingTabPane from '../CustomLoadingTabPane'; |
|||
import { GRAPH_TAB, VOTE_TAB } from '../../constants/polls/PollTabs'; |
|||
import PollVote from './PollVote'; |
|||
|
|||
const { contracts: { [VOTING_CONTRACT]: { methods: { pollExists: { cacheCall: pollExistsChainData } } } } } = drizzle; |
|||
|
|||
const hashOption = (val) => { |
|||
let hash = 0; |
|||
let i; |
|||
let chr; |
|||
|
|||
for (i = 0; i < val.length; i++) { |
|||
chr = val.charCodeAt(i); |
|||
hash = ((hash << 5) - hash) + chr; |
|||
hash |= 0; |
|||
} |
|||
|
|||
return `${hash}`; |
|||
}; |
|||
|
|||
const PollView = (props) => { |
|||
const { topicId } = props; |
|||
const userAddress = useSelector((state) => state.user.address); |
|||
const hasSignedUp = useSelector((state) => state.user.hasSignedUp); |
|||
const getPollInfoResults = useSelector((state) => state.contracts[VOTING_CONTRACT].getPollInfo); |
|||
const [getPollInfoCallHash, setGetPollInfoCallHash] = useState(null); |
|||
const [pollOptions, setPollOptions] = useState([ |
|||
{ |
|||
label: 'option 1', |
|||
hash: hashOption('option 1'), |
|||
}, |
|||
{ |
|||
label: 'option 2', |
|||
hash: hashOption('option 2'), |
|||
}, |
|||
{ |
|||
label: 'option 3', |
|||
hash: hashOption('option 3'), |
|||
}, |
|||
{ |
|||
label: 'option 4', |
|||
hash: hashOption('option 4'), |
|||
}, |
|||
{ |
|||
label: 'option 5', |
|||
hash: hashOption('option 5'), |
|||
}, |
|||
|
|||
]); |
|||
const [voteCounts, setVoteCounts] = useState([2, 8, 4, 12, 7]); |
|||
const [voteLoading, setVoteLoading] = useState(false); |
|||
const [resultsLoading, setResultsLoading] = useState(false); |
|||
const { t } = useTranslation(); |
|||
|
|||
// TODO: get vote options |
|||
|
|||
// TODO: get current results |
|||
|
|||
// TODO: check poll hash validity, add invalid view |
|||
|
|||
const pollVoteTab = useMemo(() => ( |
|||
<PollVote pollOptions={pollOptions} enableVoteChanges hasUserVoted userVoteHash={pollOptions[2].hash} /> |
|||
), [pollOptions]); |
|||
|
|||
const pollGraphTab = useMemo(() => ( |
|||
<PollGraph pollOptions={pollOptions} voteCounts={voteCounts} hasUserVoted userVoteHash={pollOptions[2].hash} /> |
|||
), [pollOptions, voteCounts]); |
|||
|
|||
const panes = useMemo(() => { |
|||
const pollVotePane = (<CustomLoadingTabPane loading={voteLoading}>{pollVoteTab}</CustomLoadingTabPane>); |
|||
const pollGraphPane = (<CustomLoadingTabPane loading={resultsLoading}>{pollGraphTab}</CustomLoadingTabPane>); |
|||
|
|||
return ([ |
|||
{ menuItem: t(VOTE_TAB.intl_display_name_id), render: () => pollVotePane }, |
|||
{ menuItem: t(GRAPH_TAB.intl_display_name_id), render: () => pollGraphPane }, |
|||
]); |
|||
}, [pollGraphTab, pollVoteTab, resultsLoading, t, voteLoading]); |
|||
|
|||
return ( |
|||
<Container id="topic-poll-container" textAlign="left"> |
|||
<Header as="h3"> |
|||
<Icon name="chart pie" size="large" /> |
|||
Do you thing asdf or fdsa? |
|||
</Header> |
|||
<Tab panes={panes} /> |
|||
</Container> |
|||
); |
|||
}; |
|||
|
|||
export default PollView; |
@ -0,0 +1,2 @@ |
|||
export const DEFAULT_OPTION_COLOR = '#3B5066'; |
|||
export const CASTED_OPTION_COLOR = '#0b2540'; |
@ -0,0 +1,16 @@ |
|||
export const VOTE_TAB = { |
|||
id: 'vote-tab', |
|||
intl_display_name_id: 'topic.poll.vote.tab.title', |
|||
}; |
|||
|
|||
export const GRAPH_TAB = { |
|||
id: 'graph-tab', |
|||
intl_display_name_id: 'topic.poll.graph.tab.title', |
|||
}; |
|||
|
|||
const pollTabs = [ |
|||
VOTE_TAB, |
|||
GRAPH_TAB, |
|||
]; |
|||
|
|||
export default pollTabs; |
Loading…
Reference in new issue