Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import AuthContext from './context/AuthContext';
import connectToBlockchain from './config';
import Layout from '@/pages/layout';
import CandidatePage from './pages/AddCandidatePage';
import CreateElection from './pages/CreateElection';

function App() {
const auth = React.useContext(AuthContext);
Expand Down Expand Up @@ -61,10 +62,11 @@ function App() {
<Route element={<Layout />}>
<Route path="/" element={<div>home</div>} />
<Route path="/voter/add" element={<LoginPage />} />
<Route path="/election">
<Route path="/elections/">
<Route path=":id" element={<div>election</div>} />
<Route path="past" element={<div>past election</div>} />
<Route path="create" element={<CreateElection />} />
<Route path="upcoming" element={<div>upcoming election</div>} />
<Route path="create" element={<div>create election</div>} />
<Route path="active" element={<div>active election</div>} />
</Route>
<Route path="/candidate/add" element={<CandidatePage />} />
Expand Down
115 changes: 115 additions & 0 deletions src/components/shared/election/create-election.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import React from 'react';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { AddElectionSchema } from '@/schemas';
import { zodResolver } from '@hookform/resolvers/zod';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/components/ui/form';
import { FormError } from '../Form-error';
import AuthContext from '@/context/AuthContext';
import { toast } from 'sonner';

export function CreateElectionForm() {
const [error, setError] = React.useState<string | undefined>('');
const [isPending, startTransition] = React.useTransition();
const auth = React.useContext(AuthContext);

const { state } = auth;

const form = useForm<z.infer<typeof AddElectionSchema>>({
resolver: zodResolver(AddElectionSchema),
defaultValues: {
purpose: '',
},
});

const onSubmit = (values: z.infer<typeof AddElectionSchema>) => {
setError('');
startTransition(async () => {
try {
if (!state.is_admin) {
toast.error('Only admin can create an election!!');
return;
}

if (state.instance !== null) {
const totalElections = await state.instance.methods.noOfElections().call();
for (let i = 1; i <= totalElections; i++) {
const electionData = await state.instance.methods
.getElection(i)
.call({ from: state.account });
if (
electionData.purpose &&
electionData.purpose.toLowerCase() === values.purpose.toLowerCase()
) {
toast.error('This election is already created');
return;
}
}

console.log('Creating election with purpose:', values.purpose);
await state.instance.methods.createElection(values.purpose).send({
from: state.account,
gas: 1000000,
});

toast.message('Election created successfully', {
description: 'A new election has been created.',
});
}
} catch (error) {
console.error(`Error: ${error}`);
toast.error('Error occurred while creating the election');
}
});
};

return (
<Form {...form}>
<form className={cn('flex flex-col gap-6')} onSubmit={form.handleSubmit(onSubmit)}>
<div className="flex flex-col items-center gap-2 text-center">
<h1 className="text-2xl font-bold">Create an Election</h1>
<p className="text-balance text-sm text-muted-foreground">
Enter the purpose of the election below.
</p>
</div>
<div className="grid gap-6">
<div className="grid gap-2">
<FormField
control={form.control}
name="purpose"
render={({ field }) => (
<FormItem>
<FormLabel htmlFor="name">Election Purpose</FormLabel>
<FormControl>
<Input
{...field}
disabled={isPending}
id="name"
placeholder="e.g., Board Member Election 2025"
type="text"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormError message={error} />
<Button type="submit" className="w-full" disabled={isPending}>
Create Election
</Button>
</div>
</form>
</Form>
);
}
15 changes: 15 additions & 0 deletions src/pages/CreateElection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { CreateElectionForm } from '@/components/shared/election/create-election';

const CreateElection = () => {
return (
<>
<div className="">
<div className="w-full max-w-xs">
<CreateElectionForm />
</div>
</div>
</>
);
};

export default CreateElection;
4 changes: 4 additions & 0 deletions src/schemas/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ export const AddCandidateSchema = z.object({
.min(1, 'Election ID must be at least 1')
.max(9999, 'Election ID cannot exceed 9999'),
});

export const AddElectionSchema = z.object({
purpose: z.string().nonempty('Name is required').min(1, 'Purpose is required').toLowerCase(),
});
Loading