diff --git a/src/App.tsx b/src/App.tsx index 8184980..a483636 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,6 +13,7 @@ import AdminElectionsPage from '@/pages/admin/Election'; import ElectionDetailPage from '@/components/shared/election/page'; import VotePage from '@/pages/election/VotePage'; import ElectionResultsPage from '@/pages/election/ResultPage'; +import ElectionDetails from '@/pages/election/ElectionPage'; function App() { const auth = React.useContext(AuthContext); @@ -85,6 +86,7 @@ function App() { }> + } /> } /> } /> admin dashboard} /> diff --git a/src/components/shared/admin/sidebar.tsx b/src/components/shared/admin/sidebar.tsx index e2aa445..c3b1f46 100644 --- a/src/components/shared/admin/sidebar.tsx +++ b/src/components/shared/admin/sidebar.tsx @@ -30,8 +30,8 @@ const sidebarItems = [ export function AdminSidebar() { const location = useLocation(); return ( -
-
+
+

Admin Panel

diff --git a/src/pages/CreateElection.tsx b/src/pages/CreateElection.tsx index 68beadc..da5c08e 100644 --- a/src/pages/CreateElection.tsx +++ b/src/pages/CreateElection.tsx @@ -1,5 +1,5 @@ import type React from 'react'; -import { useState } from 'react'; +import { useContext, useState } from 'react'; import { Link } from 'react-router'; import { Info, Plus, Trash2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; @@ -24,12 +24,14 @@ import { DialogHeader, DialogTitle, } from '@/components/ui/dialog'; +import { toast } from 'sonner'; +import AuthContext from '@/context/AuthContext'; export default function CreateElectionPage() { const [purpose, setPurpose] = useState(''); - const [candidates, setCandidates] = useState([{ id: 1, name: '', slogan: '' }]); const [successDialogOpen, setSuccessDialogOpen] = useState(false); + const { state } = useContext(AuthContext); const addCandidate = () => { setCandidates([...candidates, { id: candidates.length + 1, name: '', slogan: '' }]); @@ -49,9 +51,75 @@ export default function CreateElectionPage() { ); }; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - setSuccessDialogOpen(true); + + if (candidates.length < 2) { + toast.error('You need to have at least 2 candidates'); + return; + } + + if (!state.is_admin) { + toast.error('You do not have permission to create an election'); + return; + } + + let totalElections = 0; + let is_operation_successful = false; + + const createElectionPromise = new Promise((resolve, reject) => { + (async () => { + try { + totalElections = await state.instance!.noOfElections(); + + for (let i = 1; i <= totalElections; i++) { + const electionData = await state.instance!.getElection(i); + if ( + electionData.purpose && + electionData.purpose.toLowerCase() === purpose.toLowerCase() + ) { + throw new Error('This election is already created'); + } + } + + const tx = await state.instance!.createElection(purpose); + await tx.wait(); + + totalElections = await state.instance!.noOfElections(); + + for (const candidate of candidates) { + console.log('Adding candidate:', candidate); + const tx = await state.instance!.addCandidate( + candidate.name, + candidate.slogan, + totalElections + ); + await tx.wait(); + } + is_operation_successful = true; + resolve('Election created successfully'); + } catch (error) { + reject(error); + } + })(); + }); + + toast.promise(createElectionPromise, { + loading: 'Creating election...', + success: 'Election created successfully', + error: (error) => { + if (error.message.includes('user rejected transaction')) { + return 'Error: User rejected the transaction'; + } + return `Error while creating the election`; + }, + }); + + createElectionPromise.then(() => { + if (is_operation_successful) { + setSuccessDialogOpen(true); + } + }); }; return ( @@ -148,7 +216,9 @@ export default function CreateElectionPage() { - + diff --git a/src/pages/admin/AdminLayout.tsx b/src/pages/admin/AdminLayout.tsx index 15c8859..552cc91 100644 --- a/src/pages/admin/AdminLayout.tsx +++ b/src/pages/admin/AdminLayout.tsx @@ -3,9 +3,9 @@ import { AdminSidebar } from '@/components/shared/admin/sidebar'; const AdminLayout = () => { return ( -
+
-
+
diff --git a/src/pages/admin/Election.tsx b/src/pages/admin/Election.tsx index f3b5253..7c1492b 100644 --- a/src/pages/admin/Election.tsx +++ b/src/pages/admin/Election.tsx @@ -76,7 +76,7 @@ export default function AdminElectionsPage() {

Elections

+ )} + + {electionStatus === 'Active' && ( + + )} +
+
+ + + +
+ Election Summary + + {electionStatus} + +
+
+ +
+
+

Election ID

+

{election?.id}

+
+
+

Election Purpose

+

{election?.purpose}

+
+
+

Total Votes

+

{election?.totalVotes}

+
+
+
+
+ +

Candidates

+
+ {candidates?.map((candidate) => ( + + ))} +
+ +
+ ); +} + +interface CandidateCardProps { + name: string; + id: string; + slogan: string; + voteCount: number; +} + +function CandidateCard({ name, id, slogan, voteCount }: CandidateCardProps) { + return ( + + + {name} + Candidate ID: {id} + + +
+

Slogan

+

{slogan}

+
+ +
+

Vote Count

+

{voteCount}

+
+
+
+ ); +}