Browse Source

feat: poll view improvements

develop
Ezerous 4 years ago
parent
commit
e81d1e8426
  1. 2
      packages/concordia-app/public/locales/en/translation.json
  2. 56
      packages/concordia-app/src/components/PollView/PollGraph/PollChartBar/index.jsx
  3. 49
      packages/concordia-app/src/components/PollView/PollGraph/PollChartDonut/index.jsx
  4. 117
      packages/concordia-app/src/components/PollView/PollGraph/index.jsx
  5. 4
      packages/concordia-app/src/components/PollView/PollGraph/styles.css
  6. 12
      packages/concordia-app/src/components/PollView/index.jsx
  7. 4
      packages/concordia-app/src/constants/polls/PollGraph.js

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

@ -90,7 +90,7 @@
"topic.poll.invalid.data.header": "This topic has a poll but the data are untrusted!",
"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.results.votes.count": "{{totalVotes}} votes casted",
"topic.poll.tab.results.votes.count": "Total votes: {{totalVotes}}",
"topic.poll.tab.vote.form.button.submit": "Submit",
"topic.poll.tab.vote.form.radio.label": "Select one of the options:",
"topic.poll.tab.vote.title": "Vote",

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

@ -0,0 +1,56 @@
import React, { useMemo } from 'react';
import Chart from 'react-apexcharts';
import PropTypes from 'prop-types';
import { CHART_TYPE_BAR } from '../../../../constants/polls/PollGraph';
const PollChartBar = (props) => {
const { pollOptions, voteCounts } = props;
const chartOptions = useMemo(() => ({
chart: {
id: 'chart-bar',
},
theme: {
palette: 'palette8',
},
plotOptions: {
bar: {
horizontal: true,
distributed: true,
},
},
xaxis: {
categories: pollOptions,
tickAmount: 1,
labels: {
formatter(val) {
if (val.toFixed) return val.toFixed(0);
return val;
},
},
},
tooltip: {
enabled: false,
},
}), [pollOptions]);
const chartSeries = useMemo(() => [{
name: 'Votes',
data: voteCounts,
}], [voteCounts]);
return (
<Chart
options={chartOptions}
series={chartSeries}
type={CHART_TYPE_BAR}
/>
);
};
PollChartBar.propTypes = {
pollOptions: PropTypes.arrayOf(PropTypes.string).isRequired,
voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired,
};
export default PollChartBar;

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

@ -0,0 +1,49 @@
import React, { useMemo } from 'react';
import Chart from 'react-apexcharts';
import PropTypes from 'prop-types';
import { CHART_TYPE_DONUT } from '../../../../constants/polls/PollGraph';
const PollChartDonut = (props) => {
const { pollOptions, voteCounts } = props;
const chartOptions = useMemo(() => ({
chart: {
id: 'chart-donut',
},
theme: {
palette: 'palette8',
},
plotOptions: {
pie: {
donut: {
labels: {
show: true,
total: {
show: true,
label: 'Total Votes',
},
},
},
},
},
labels: pollOptions,
tooltip: {
enabled: false,
},
}), [pollOptions]);
return (
<Chart
options={chartOptions}
series={voteCounts}
type={CHART_TYPE_DONUT}
/>
);
};
PollChartDonut.propTypes = {
pollOptions: PropTypes.arrayOf(PropTypes.string).isRequired,
voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired,
};
export default PollChartDonut;

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

@ -1,79 +1,76 @@
import React, { useMemo } from 'react';
import Chart from 'react-apexcharts';
import { Grid, Header } from 'semantic-ui-react';
import { Grid, Header, Tab } 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';
import PollChartBar from './PollChartBar';
import PollChartDonut from './PollChartDonut';
import './styles.css';
const PollGraph = (props) => {
const {
pollOptions, voteCounts, hasUserVoted, selectedOptionIndex,
} = props;
const { pollOptions, voteCounts } = props;
const { t } = useTranslation();
const chartOptions = useMemo(() => ({
chart: {
id: 'topic-poll',
},
plotOptions: {
bar: {
horizontal: true,
},
},
colors: [
(value) => {
if (hasUserVoted && value.dataPointIndex === selectedOptionIndex) {
return CASTED_OPTION_COLOR;
}
return DEFAULT_OPTION_COLOR;
},
],
xaxis: {
categories: pollOptions,
},
}), [hasUserVoted, pollOptions, selectedOptionIndex]);
const panes = useMemo(() => {
const chartBarPane = (
<Tab.Pane attached={false}>
<Grid columns="equal">
<Grid.Row>
<Grid.Column />
<Grid.Column width={8}>
<PollChartBar
pollOptions={pollOptions}
voteCounts={voteCounts}
/>
</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>
</Tab.Pane>
);
const chartDonutPane = (
<Tab.Pane attached={false}>
<Grid columns="equal">
<Grid.Row>
<Grid.Column />
<Grid.Column width={8}>
<PollChartDonut
pollOptions={pollOptions}
voteCounts={voteCounts}
/>
</Grid.Column>
<Grid.Column />
</Grid.Row>
<Grid.Row />
</Grid>
</Tab.Pane>
);
const chartSeries = useMemo(() => [{
name: 'votes',
data: voteCounts,
}], [voteCounts]);
return ([
{ menuItem: { key: 'chart-bar', icon: 'chart bar' }, render: () => chartBarPane },
{ menuItem: { key: 'chart-donut', icon: 'chart pie' }, render: () => chartDonutPane },
]);
}, [pollOptions, t, 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>
<Tab
menu={{ secondary: true }}
panes={panes}
/>
);
};
PollGraph.defaultProps = {
hasUserVoted: false,
selectedOptionIndex: '',
};
PollGraph.propTypes = {
pollOptions: PropTypes.arrayOf(PropTypes.string).isRequired,
voteCounts: PropTypes.arrayOf(PropTypes.number).isRequired,
hasUserVoted: PropTypes.bool,
selectedOptionIndex: PropTypes.string,
};
export default PollGraph;

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

@ -0,0 +1,4 @@
#topic-poll-container .ui.segment.tab {
box-shadow: none;
border: none;
}

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

@ -1,4 +1,6 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, {
useEffect, useMemo, useState,
} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { VOTING_CONTRACT } from 'concordia-shared/src/constants/contracts/ContractNames';
import {
@ -145,12 +147,10 @@ const PollView = (props) => {
<PollGraph
pollOptions={pollOptions}
voteCounts={voteCounts}
hasUserVoted={userHasVoted}
userVoteIndex={userVoteIndex}
/>
)
: null
), [chainDataLoading, orbitDataLoading, pollOptions, userHasVoted, userVoteIndex, voteCounts]);
), [chainDataLoading, orbitDataLoading, pollOptions, voteCounts]);
const panes = useMemo(() => {
const pollVotePane = (
@ -165,8 +165,8 @@ const PollView = (props) => {
);
return ([
{ menuItem: t(VOTE_TAB.intl_display_name_id), render: () => pollVotePane },
{ menuItem: t(GRAPH_TAB.intl_display_name_id), render: () => pollGraphPane },
{ menuItem: t(VOTE_TAB.intl_display_name_id), render: () => pollVotePane },
]);
}, [chainDataLoading, orbitDataLoading, pollGraphTab, pollVoteTab, t]);
@ -182,7 +182,7 @@ const PollView = (props) => {
{!chainDataLoading && !orbitDataLoading ? (
<>
<Header as="h3">
<Icon name="chart pie" size="large" />
<Icon name="chart area" size="large" />
{pollQuestion}
</Header>
<Tab panes={panes} />

4
packages/concordia-app/src/constants/polls/PollGraph.js

@ -1,2 +1,2 @@
export const DEFAULT_OPTION_COLOR = '#3B5066';
export const CASTED_OPTION_COLOR = '#0b2540';
export const CHART_TYPE_BAR = 'bar';
export const CHART_TYPE_DONUT = 'donut';

Loading…
Cancel
Save