Browse Source

feat: add ability to remove vote

develop
Ezerous 4 years ago
parent
commit
da1d9727d6
  1. 3
      packages/concordia-app/public/locales/en/translation.json
  2. 7
      packages/concordia-app/src/components/PollView/PollGraph/PollChartDonut/index.jsx
  3. 40
      packages/concordia-app/src/components/PollView/PollGraph/index.jsx
  4. 4
      packages/concordia-app/src/components/PollView/PollGraph/styles.css
  5. 67
      packages/concordia-app/src/components/PollView/PollVote/index.jsx
  6. 3
      packages/concordia-app/src/components/PollView/index.jsx

3
packages/concordia-app/public/locales/en/translation.json

@ -91,7 +91,10 @@
"topic.poll.invalid.data.sub.header": "The poll data downloaded from the poster have been tampered with.", "topic.poll.invalid.data.sub.header": "The poll data downloaded from the poster have been tampered with.",
"topic.poll.tab.graph.title": "Results", "topic.poll.tab.graph.title": "Results",
"topic.poll.tab.results.votes.count": "Total votes: {{totalVotes}}", "topic.poll.tab.results.votes.count": "Total votes: {{totalVotes}}",
"topic.poll.tab.results.user.vote": "You voted: {{userVote}}",
"topic.poll.tab.vote.no.changes": "This poll does not allow vote changes.",
"topic.poll.tab.vote.form.button.submit": "Submit", "topic.poll.tab.vote.form.button.submit": "Submit",
"topic.poll.tab.vote.form.button.unvote": "Remove Vote",
"topic.poll.tab.vote.form.radio.label": "Select one of the options:", "topic.poll.tab.vote.form.radio.label": "Select one of the options:",
"topic.poll.tab.vote.title": "Vote", "topic.poll.tab.vote.title": "Vote",
"username.selector.error.username.empty.message": "Username is required", "username.selector.error.username.empty.message": "Username is required",

7
packages/concordia-app/src/components/PollView/PollGraph/PollChartDonut/index.jsx

@ -18,10 +18,6 @@ const PollChartDonut = (props) => {
donut: { donut: {
labels: { labels: {
show: true, show: true,
total: {
show: true,
label: 'Total Votes',
},
}, },
}, },
}, },
@ -30,6 +26,9 @@ const PollChartDonut = (props) => {
tooltip: { tooltip: {
enabled: false, enabled: false,
}, },
legend: {
position: 'bottom',
},
}), [pollOptions]); }), [pollOptions]);
return ( return (

40
packages/concordia-app/src/components/PollView/PollGraph/index.jsx

@ -7,9 +7,28 @@ import PollChartDonut from './PollChartDonut';
import './styles.css'; import './styles.css';
const PollGraph = (props) => { const PollGraph = (props) => {
const { pollOptions, voteCounts } = props; const { pollOptions, voteCounts, userVoteIndex } = props;
const { t } = useTranslation(); const { t } = useTranslation();
const footer = useMemo(() => (
<>
{' '}
<Header as="h4">
{t('topic.poll.tab.results.votes.count', {
totalVotes: voteCounts.reduce((accumulator, voteCount) => accumulator + voteCount, 0),
})}
</Header>
{userVoteIndex !== -1
&& (
<Header as="h4">
{t('topic.poll.tab.results.user.vote', {
userVote: pollOptions[userVoteIndex],
})}
</Header>
)}
</>
), [pollOptions, t, userVoteIndex, voteCounts]);
const panes = useMemo(() => { const panes = useMemo(() => {
const chartBarPane = ( const chartBarPane = (
<Tab.Pane attached={false}> <Tab.Pane attached={false}>
@ -26,11 +45,7 @@ const PollGraph = (props) => {
</Grid.Row> </Grid.Row>
<Grid.Row> <Grid.Row>
<Grid.Column textAlign="center"> <Grid.Column textAlign="center">
<Header as="h4"> {footer}
{t('topic.poll.tab.results.votes.count', {
totalVotes: voteCounts.reduce((accumulator, voteCount) => accumulator + voteCount, 0),
})}
</Header>
</Grid.Column> </Grid.Column>
</Grid.Row> </Grid.Row>
</Grid> </Grid>
@ -49,7 +64,11 @@ const PollGraph = (props) => {
</Grid.Column> </Grid.Column>
<Grid.Column /> <Grid.Column />
</Grid.Row> </Grid.Row>
<Grid.Row /> <Grid.Row>
<Grid.Column textAlign="center">
{footer}
</Grid.Column>
</Grid.Row>
</Grid> </Grid>
</Tab.Pane> </Tab.Pane>
); );
@ -58,7 +77,7 @@ const PollGraph = (props) => {
{ menuItem: { key: 'chart-bar', icon: 'chart bar' }, render: () => chartBarPane }, { menuItem: { key: 'chart-bar', icon: 'chart bar' }, render: () => chartBarPane },
{ menuItem: { key: 'chart-donut', icon: 'chart pie' }, render: () => chartDonutPane }, { menuItem: { key: 'chart-donut', icon: 'chart pie' }, render: () => chartDonutPane },
]); ]);
}, [pollOptions, t, voteCounts]); }, [footer, pollOptions, voteCounts]);
return ( return (
<Tab <Tab
@ -68,9 +87,14 @@ const PollGraph = (props) => {
); );
}; };
PollGraph.defaultProps = {
userVoteIndex: -1,
};
PollGraph.propTypes = { PollGraph.propTypes = {
pollOptions: PropTypes.arrayOf(PropTypes.string).isRequired, pollOptions: PropTypes.arrayOf(PropTypes.string).isRequired,
voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired, voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired,
userVoteIndex: PropTypes.number,
}; };
export default PollGraph; export default PollGraph;

4
packages/concordia-app/src/components/PollView/PollGraph/styles.css

@ -2,3 +2,7 @@
box-shadow: none; box-shadow: none;
border: none; border: none;
} }
#topic-poll-container h4 {
margin-top: 0.5rem;
}

67
packages/concordia-app/src/components/PollView/PollVote/index.jsx

@ -1,9 +1,11 @@
import React, { useState } from 'react'; import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Form } from 'semantic-ui-react'; import { useSelector } from 'react-redux';
import { Button, Form, Header } from 'semantic-ui-react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames'; import { VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import { drizzle } from '../../../redux/store'; import { drizzle } from '../../../redux/store';
import { TRANSACTION_ERROR, TRANSACTION_SUCCESS } from '../../../constants/TransactionStatus';
const { contracts: { [VOTING_CONTRACT]: { methods: { vote } } } } = drizzle; const { contracts: { [VOTING_CONTRACT]: { methods: { vote } } } } = drizzle;
@ -11,19 +13,57 @@ const PollVote = (props) => {
const { const {
topicId, account, pollOptions, enableVoteChanges, hasUserVoted, userVoteIndex, topicId, account, pollOptions, enableVoteChanges, hasUserVoted, userVoteIndex,
} = props; } = props;
const transactionStack = useSelector((state) => state.transactionStack);
const transactions = useSelector((state) => state.transactions);
const [voteCacheSendStackId, setVoteCacheSendStackId] = useState('');
const [selectedOptionIndex, setSelectedOptionIndex] = useState(userVoteIndex); const [selectedOptionIndex, setSelectedOptionIndex] = useState(userVoteIndex);
const [voting, setVoting] = useState(''); const [voting, setVoting] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
const onOptionSelected = (e, { value }) => { const onOptionSelected = (e, { value }) => {
setSelectedOptionIndex(value); setSelectedOptionIndex(value);
}; };
useEffect(() => {
setSelectedOptionIndex(userVoteIndex);
}, [userVoteIndex]);
const onCastVote = () => { const onCastVote = () => {
setVoting(true); setVoting(true);
vote.cacheSend(...[topicId, selectedOptionIndex + 1], { from: account }); setVoteCacheSendStackId(vote.cacheSend(...[topicId, selectedOptionIndex + 1], { from: account }));
}; };
const onUnvote = (e) => {
e.preventDefault();
setVoting(true);
setVoteCacheSendStackId(vote.cacheSend(...[topicId, 0], { from: account }));
};
useEffect(() => {
if (voting && transactionStack && transactionStack[voteCacheSendStackId]
&& transactions[transactionStack[voteCacheSendStackId]]) {
if (transactions[transactionStack[voteCacheSendStackId]].status === TRANSACTION_ERROR
|| transactions[transactionStack[voteCacheSendStackId]].status === TRANSACTION_SUCCESS) {
setVoting(false);
}
}
}, [transactionStack, transactions, voteCacheSendStackId, voting]);
if (hasUserVoted && !enableVoteChanges) {
return (
<>
<Header as="h4">
{t('topic.poll.tab.results.user.vote', {
userVote: pollOptions[userVoteIndex],
})}
</Header>
<div>
{t('topic.poll.tab.vote.no.changes')}
</div>
</>
);
}
return ( return (
<Form onSubmit={onCastVote}> <Form onSubmit={onCastVote}>
<Form.Group grouped> <Form.Group grouped>
@ -34,17 +74,28 @@ const PollVote = (props) => {
label={pollOption} label={pollOption}
value={index} value={index}
checked={index === selectedOptionIndex} checked={index === selectedOptionIndex}
disabled={hasUserVoted && !enableVoteChanges && index !== selectedOptionIndex} disabled={voting}
onChange={onOptionSelected} onChange={onOptionSelected}
/> />
))} ))}
</Form.Group> </Form.Group>
<Form.Button <Button
type="submit" type="submit"
disabled={voting || (hasUserVoted && !enableVoteChanges) || (selectedOptionIndex === userVoteIndex)} className="primary-button"
disabled={voting || (selectedOptionIndex === userVoteIndex)}
> >
{t('topic.poll.tab.vote.form.button.submit')} {t('topic.poll.tab.vote.form.button.submit')}
</Form.Button> </Button>
{hasUserVoted && enableVoteChanges
&& (
<Button
type="submit"
disabled={voting}
onClick={onUnvote}
>
{t('topic.poll.tab.vote.form.button.unvote')}
</Button>
)}
</Form> </Form>
); );
}; };

3
packages/concordia-app/src/components/PollView/index.jsx

@ -147,10 +147,11 @@ const PollView = (props) => {
<PollGraph <PollGraph
pollOptions={pollOptions} pollOptions={pollOptions}
voteCounts={voteCounts} voteCounts={voteCounts}
userVoteIndex={userVoteIndex}
/> />
) )
: null : null
), [chainDataLoading, orbitDataLoading, pollOptions, voteCounts]); ), [chainDataLoading, orbitDataLoading, pollOptions, userVoteIndex, voteCounts]);
const panes = useMemo(() => { const panes = useMemo(() => {
const pollVotePane = ( const pollVotePane = (

Loading…
Cancel
Save