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
117 changes: 117 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-navigation-menu": "^1.2.5",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-progress": "^1.1.2",
"@radix-ui/react-radio-group": "^1.2.3",
"@radix-ui/react-select": "^2.1.6",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tabs": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/vite": "^4.0.9",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
Expand Down
16 changes: 13 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import CandidatePage from '@/pages/AddCandidatePage';
import CreateElection from '@/pages/CreateElection';
import HomePage from '@/pages/Home';
import AdminLayout from '@/pages/admin/AdminLayout';
import AdminVerifyVotersPage from './pages/admin/Verify-voters';
import AdminVerifyVotersPage from '@/pages/admin/Verify-voters';
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';

function App() {
const auth = React.useContext(AuthContext);
Expand Down Expand Up @@ -70,13 +74,19 @@ function App() {
<Route path="/" element={<HomePage />} />
<Route path="/voter/add" element={<LoginPage />} />
<Route path="/elections/">
<Route path=":id" element={<div>election</div>} />
<Route path=":id">
<Route index element={<ElectionDetailPage />} />
<Route path="vote" element={<VotePage />} />
<Route path="results" element={<ElectionResultsPage />} />
</Route>
<Route path="past" element={<div>past election</div>} />
<Route path="create" element={<CreateElection />} />
<Route path="upcoming" element={<div>upcoming election</div>} />
<Route path="active" element={<div>active election</div>} />
</Route>

<Route path="/admin" element={<AdminLayout />}>
<Route path="elections" element={<AdminElectionsPage />} />
<Route path="create-election" element={<CreateElection />} />
<Route index element={<div>admin dashboard</div>} />
<Route path="verify-voters" element={<AdminVerifyVotersPage />} />
</Route>
Expand Down
9 changes: 5 additions & 4 deletions src/components/shared/admin/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Link } from 'react-router';
import { Link, useLocation } from 'react-router';
import { BarChart, Home, Users, Vote } from 'lucide-react';

import { Button } from '@/components/ui/button';
Expand Down Expand Up @@ -28,8 +28,9 @@ const sidebarItems = [
];

export function AdminSidebar() {
const location = useLocation();
return (
<div className="hidden md:block">
<div className="hidden md:block ">
<div className="space-y-4 py-4">
<div className="px-3 py-2">
<h2 className="mb-2 px-4 text-lg font-semibold tracking-tight">Admin Panel</h2>
Expand All @@ -39,8 +40,8 @@ export function AdminSidebar() {
key={item.href}
variant="ghost"
className={cn(
'w-full justify-start',
item.href === '/admin/verify-voters' && 'bg-accent text-accent-foreground'
'w-full justify-start transition-colors duration-200 ease-in-out hover:bg-accent hover:text-accent-foreground',
item.href === location.pathname && 'bg-accent text-accent-foreground'
)}
asChild
>
Expand Down
5 changes: 1 addition & 4 deletions src/components/shared/auth/Add-candidate-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ export function AddCandidateForm() {

try {
if (state.instance !== null) {
await state.instance.methods.addCandidate(values.name, values.slogan, electionid).send({
from: state.account,
gas: 1000000,
});
await state.instance.methods.addCandidate(values.name, values.slogan, electionid);

toast.success('Candidate added successfully');
form.reset();
Expand Down
5 changes: 1 addition & 4 deletions src/components/shared/auth/Login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,7 @@ export function LoginForm() {
}

if (state.instance !== null) {
await state.instance.addVoter(state.account, values.name).send({
from: state.account,
gas: 1000000,
});
await state.instance.addVoter(state.account, values.name);

dispatch({
type: 'REGISTER',
Expand Down
62 changes: 62 additions & 0 deletions src/components/shared/candidate-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Link } from 'react-router';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Progress } from '@/components/ui/progress';

interface Candidate {
id: number;
name: string;
slogan: string;
votes?: number;
percentage?: number;
position?: number;
winner?: boolean;
}

interface CandidateCardProps {
candidate: Candidate;
electionId: number;
showResults?: boolean;
}

export function CandidateCard({ candidate, electionId, showResults = false }: CandidateCardProps) {
return (
<Card className={candidate.winner ? 'border-primary/50 bg-primary/5' : ''}>
<CardHeader className="pb-3">
<div className="flex items-start justify-between">
<div>
<CardTitle className="text-lg">{candidate.name}</CardTitle>
{candidate.position && (
<div className="mt-1">
Rank: {candidate.position}
{candidate.winner && (
<Badge className="ml-2 bg-primary text-primary-foreground">Winner</Badge>
)}
</div>
)}
</div>
</div>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground">{candidate.slogan}</p>

{showResults && candidate.votes !== undefined && candidate.percentage !== undefined && (
<div className="mt-4 space-y-2">
<div className="flex items-center justify-between text-sm">
<span>Votes: {candidate.votes}</span>
<span>{candidate.percentage}%</span>
</div>
<Progress value={candidate.percentage} className="h-2" />
</div>
)}
</CardContent>
<CardFooter>
<Button variant="outline" size="sm" className="w-full" asChild>
<Link to={`/elections/${electionId}/vote`}>Vote for this candidate</Link>
</Button>
</CardFooter>
</Card>
);
}
6 changes: 1 addition & 5 deletions src/components/shared/election/create-election.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,14 @@ export function CreateElectionForm() {
}
}

await state.instance.createElection(values.purpose).send({
from: state.account,
gas: 1000000,
});
await state.instance.createElection(values.purpose);

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');
}
});
};
Expand Down
Loading
Loading