Skip to content

Commit 16b1f1e

Browse files
authored
Merge pull request #215 from dedis/aelalamy-result-sort
Individual Results Feature
2 parents 0f99cbf + e6616b3 commit 16b1f1e

File tree

5 files changed

+305
-105
lines changed

5 files changed

+305
-105
lines changed

web/frontend/src/language/en.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@
257257
"actionNotAvailable": "Action not available",
258258
"uninitialized": "Uninitialized",
259259
"actionTextVoter1": "The form is not open yet, you can come back later to vote once it is open.",
260-
"actionTextVoter2": "The results of the form are not available yet."
260+
"actionTextVoter2": "The results of the form are not available yet.",
261+
"resIndiv": "Individual",
262+
"resGroup": "Grouped"
261263
}
262264
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { FC } from 'react';
2+
import { RankResults, SelectResults, TextResults } from 'types/form';
3+
import SelectResult from './components/SelectResult';
4+
import RankResult from './components/RankResult';
5+
import TextResult from './components/TextResult';
6+
import {
7+
ID,
8+
RANK,
9+
RankQuestion,
10+
SELECT,
11+
SUBJECT,
12+
SelectQuestion,
13+
Subject,
14+
SubjectElement,
15+
TEXT,
16+
} from 'types/configuration';
17+
import { useParams } from 'react-router-dom';
18+
import useForm from 'components/utils/useForm';
19+
import { useConfigurationOnly } from 'components/utils/useConfiguration';
20+
21+
type GroupedResultProps = {
22+
rankResult: RankResults;
23+
selectResult: SelectResults;
24+
textResult: TextResults;
25+
};
26+
27+
// Functional component that displays the result of the votes
28+
const GroupedResult: FC<GroupedResultProps> = ({ rankResult, selectResult, textResult }) => {
29+
const { formId } = useParams();
30+
31+
const { result, configObj } = useForm(formId);
32+
const configuration = useConfigurationOnly(configObj);
33+
34+
const SubjectElementResultDisplay = (element: SubjectElement) => {
35+
return (
36+
<div className="pl-4 pb-4 sm:pl-6 sm:pb-6">
37+
<h2 className="text-lg pb-2">{element.Title}</h2>
38+
{element.Type === RANK && rankResult.has(element.ID) && (
39+
<RankResult rank={element as RankQuestion} rankResult={rankResult.get(element.ID)} />
40+
)}
41+
{element.Type === SELECT && selectResult.has(element.ID) && (
42+
<SelectResult
43+
select={element as SelectQuestion}
44+
selectResult={selectResult.get(element.ID)}
45+
/>
46+
)}
47+
{element.Type === TEXT && textResult.has(element.ID) && (
48+
<TextResult textResult={textResult.get(element.ID)} />
49+
)}
50+
</div>
51+
);
52+
};
53+
54+
const displayResults = (subject: Subject) => {
55+
console.log(result);
56+
return (
57+
<div key={subject.ID}>
58+
<h2 className="text-xl pt-1 pb-1 sm:pt-2 sm:pb-2 border-t font-bold text-gray-600">
59+
{subject.Title}
60+
</h2>
61+
{subject.Order.map((id: ID) => (
62+
<div key={id}>
63+
{subject.Elements.get(id).Type === SUBJECT ? (
64+
<div className="pl-4 sm:pl-6">
65+
{displayResults(subject.Elements.get(id) as Subject)}
66+
</div>
67+
) : (
68+
SubjectElementResultDisplay(subject.Elements.get(id))
69+
)}
70+
</div>
71+
))}
72+
</div>
73+
);
74+
};
75+
76+
return (
77+
<div>
78+
<div className="flex flex-col">
79+
{configuration.Scaffold.map((subject: Subject) => displayResults(subject))}
80+
</div>
81+
<div className="flex my-4"></div>
82+
</div>
83+
);
84+
};
85+
86+
export default GroupedResult;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { FC, useEffect, useState } from 'react';
2+
import { RankResults, SelectResults, TextResults } from 'types/form';
3+
import SelectResult from './components/SelectResult';
4+
import RankResult from './components/RankResult';
5+
import TextResult from './components/TextResult';
6+
import { useTranslation } from 'react-i18next';
7+
import {
8+
ID,
9+
RANK,
10+
RankQuestion,
11+
SELECT,
12+
SUBJECT,
13+
SelectQuestion,
14+
Subject,
15+
SubjectElement,
16+
TEXT,
17+
} from 'types/configuration';
18+
import { useParams } from 'react-router-dom';
19+
import useForm from 'components/utils/useForm';
20+
import { useConfigurationOnly } from 'components/utils/useConfiguration';
21+
22+
type IndividualResultProps = {
23+
rankResult: RankResults;
24+
selectResult: SelectResults;
25+
textResult: TextResults;
26+
ballotNumber: number;
27+
};
28+
// Functional component that displays the result of the votes
29+
const IndividualResult: FC<IndividualResultProps> = ({
30+
rankResult,
31+
selectResult,
32+
textResult,
33+
ballotNumber,
34+
}) => {
35+
const { formId } = useParams();
36+
const { t } = useTranslation();
37+
const { configObj } = useForm(formId);
38+
const configuration = useConfigurationOnly(configObj);
39+
40+
const [currentID, setCurrentID] = useState<number>(0);
41+
42+
const SubjectElementResultDisplay = (element: SubjectElement) => {
43+
return (
44+
<div className="pl-4 pb-4 sm:pl-6 sm:pb-6">
45+
<h2 className="text-lg pb-2">{element.Title}</h2>
46+
{element.Type === RANK && rankResult.has(element.ID) && (
47+
<RankResult
48+
rank={element as RankQuestion}
49+
rankResult={[rankResult.get(element.ID)[currentID]]}
50+
/>
51+
)}
52+
{element.Type === SELECT && selectResult.has(element.ID) && (
53+
<SelectResult
54+
select={element as SelectQuestion}
55+
selectResult={[selectResult.get(element.ID)[currentID]]}
56+
/>
57+
)}
58+
{element.Type === TEXT && textResult.has(element.ID) && (
59+
<TextResult textResult={[textResult.get(element.ID)[currentID]]} />
60+
)}
61+
</div>
62+
);
63+
};
64+
65+
const displayResults = (subject: Subject) => {
66+
return (
67+
<div key={subject.ID}>
68+
<h2 className="text-xl pt-1 pb-1 sm:pt-2 sm:pb-2 border-t font-bold text-gray-600">
69+
{subject.Title}
70+
</h2>
71+
{subject.Order.map((id: ID) => (
72+
<div key={id}>
73+
{subject.Elements.get(id).Type === SUBJECT ? (
74+
<div className="pl-4 sm:pl-6">
75+
{displayResults(subject.Elements.get(id) as Subject)}
76+
</div>
77+
) : (
78+
SubjectElementResultDisplay(subject.Elements.get(id))
79+
)}
80+
</div>
81+
))}
82+
</div>
83+
);
84+
};
85+
useEffect(() => {
86+
configuration.Scaffold.map((subject: Subject) => displayResults(subject));
87+
}, [currentID]);
88+
89+
const handleNext = (): void => {
90+
setCurrentID((currentID + 1) % ballotNumber);
91+
};
92+
93+
const handlePrevious = (): void => {
94+
setCurrentID((currentID - 1 + ballotNumber) % ballotNumber);
95+
};
96+
97+
return (
98+
<div>
99+
<div className="flex flex-col">
100+
<div className="grid grid-cols-9 font-medium rounded-md border-t stext-sm text-center align-center justify-middle text-gray-700 bg-white py-2">
101+
<button
102+
onClick={handlePrevious}
103+
className="items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
104+
{t('previous')}
105+
</button>
106+
<div className="grow col-span-7 p-2">{'Ballot ' + (currentID + 1)}</div>
107+
<button
108+
onClick={handleNext}
109+
className="ml-3 relative align-right items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
110+
{t('next')}
111+
</button>
112+
</div>
113+
{configuration.Scaffold.map((subject: Subject) => displayResults(subject))}
114+
</div>
115+
</div>
116+
);
117+
};
118+
119+
export default IndividualResult;

0 commit comments

Comments
 (0)