From ed4a52d3b9d955ea2f3d678c0778583f874e21ac Mon Sep 17 00:00:00 2001 From: Eivind Dalholt Date: Sun, 24 Sep 2023 21:41:05 +0200 Subject: [PATCH] feat: possible to duplicate a votation (#192) * feat: possible to duplicate an ended votation * test: add new method * feat: add duplicate button to not started votation --- frontend/src/components/EditAssembly.tsx | 39 +++++++++++++++++------ frontend/src/components/Results.tsx | 20 ++++++++++-- frontend/src/components/VotationPanel.tsx | 21 ++++++++---- frontend/src/tests/Results.test.tsx | 6 +++- 4 files changed, 67 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/EditAssembly.tsx b/frontend/src/components/EditAssembly.tsx index 6e97d55..2995159 100644 --- a/frontend/src/components/EditAssembly.tsx +++ b/frontend/src/components/EditAssembly.tsx @@ -21,13 +21,14 @@ import { import { getVotations } from "../services/votation"; import { AssemblyType } from "../types/assembly"; import VotationPanel from "./VotationPanel"; -import { VoteType } from "../types/votes"; +import { OptionType, VoteType } from "../types/votes"; import { Results } from "./Results"; import { useMediaQuery } from "@mantine/hooks"; import useWebSocket from "react-use-websocket"; +import { showNotification } from "@mantine/notifications"; export function EditAssembly(state: { group: UserDataGroupType }) { - const breakpoint = useMediaQuery("(min-width: 800px)"); + const breakpoint = useMediaQuery("(min-width: 1010px)"); const [group, setGroup] = useState(state.group); const [votations, setVotations] = useState([]); const [assembly, setAssembly] = useState(); @@ -108,7 +109,7 @@ export function EditAssembly(state: { group: UserDataGroupType }) { navigate("/admin"); } - async function addCase() { + async function addCase(votationTemplate?: VoteType) { // Creates a temporary case to the votation list, this is not saved as a votation in the database before the required values are provided. // Only one element can exist at the same time, the user therefore has to finish editing the current temporary element before creating another one. if (!votations.some((votation) => votation._id == "temp")) { @@ -117,17 +118,22 @@ export function EditAssembly(state: { group: UserDataGroupType }) { ...votations, { _id: "temp", - title: "Placeholder", + title: votationTemplate ? votationTemplate.title : "Placeholder", caseNumber: 0.1, - voteText: "", + voteText: votationTemplate ? votationTemplate.voteText : "", voted: [], - options: [], + options: votationTemplate ? votationTemplate.options : [], isFinished: false, isActive: false, numberParticipants: 0, editable: true, }, ]); + } else { + showNotification({ + title: "Error", + message: "You can only create one new votation at a time", + }); } } @@ -288,15 +294,19 @@ export function EditAssembly(state: { group: UserDataGroupType }) { )} - {votations.length < 1 ? ( - There are currently no cases + There are currently no votations in this assembly. ) : ( a.caseNumber - b.caseNumber) .map((vote: VoteType) => { return vote.isFinished ? ( - + + addCase(votationTemplate) + } + /> ) : ( + addCase(votationTemplate) + } /> ); })} diff --git a/frontend/src/components/Results.tsx b/frontend/src/components/Results.tsx index 3e9ee0e..30cfdde 100644 --- a/frontend/src/components/Results.tsx +++ b/frontend/src/components/Results.tsx @@ -1,9 +1,22 @@ -import { Accordion, Container, Card, Progress, Text } from "@mantine/core"; +import { + Accordion, + Container, + Card, + Progress, + Text, + Button, +} from "@mantine/core"; import { useMediaQuery } from "@mantine/hooks"; import { VoteType } from "../types/votes"; import { useEffect, useState } from "react"; -export function Results({ votation }: { votation: VoteType }) { +export function Results({ + votation, + addCase, +}: { + votation: VoteType; + addCase: (votation: VoteType) => void; +}) { const matches = useMediaQuery("(min-width: 400px)"); const [isOpen, setIsOpen] = useState(false); @@ -99,6 +112,9 @@ export function Results({ votation }: { votation: VoteType }) { votation.voted.length} of {votation.numberParticipants || 0}{" "} participants did not vote + diff --git a/frontend/src/components/VotationPanel.tsx b/frontend/src/components/VotationPanel.tsx index 99e6ff7..33f465a 100644 --- a/frontend/src/components/VotationPanel.tsx +++ b/frontend/src/components/VotationPanel.tsx @@ -41,6 +41,7 @@ function VotationPanel({ setIsChanged, assemblyStatus, initEditable, + addCase, }: { accordionActiveTabs: string[]; setAccordionActiveTabs: (tabs: string[]) => void; @@ -50,6 +51,7 @@ function VotationPanel({ setIsChanged: React.Dispatch>; assemblyStatus: boolean; initEditable: boolean; + addCase: (votation: VoteType) => void; }) { const [editable, setEditable] = useState(initEditable); const [isFinishChecked, setIsFinishChecked] = useState(false); @@ -69,7 +71,6 @@ function VotationPanel({ }); const { classes } = useStyles(); const matches = useMediaQuery("(min-width: 400px)"); - const participantMatch = useMediaQuery("(min-width: 500px)"); const [defaultOptions] = useState(["Yes", "No", "Blank"]); const [options, setOptions] = useState( votation.options.map((option) => { @@ -282,7 +283,8 @@ function VotationPanel({ +