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

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"@hookform/resolvers": "^4.1.3",
"@radix-ui/react-alert-dialog": "^1.1.6",
"@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-dropdown-menu": "^2.1.6",
"@radix-ui/react-label": "^2.1.2",
Expand Down
2 changes: 2 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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';
import ResultsPage from './pages/election/ResultsPage';

function App() {
const auth = React.useContext(AuthContext);
Expand Down Expand Up @@ -91,6 +92,7 @@ function App() {
<Route path="create-election" element={<CreateElection />} />
<Route index element={<div>admin dashboard</div>} />
<Route path="verify-voters" element={<AdminVerifyVotersPage />} />
<Route path="results" element={<ResultsPage />} />
</Route>
<Route path="/candidate/add" element={<CandidatePage />} />
<Route path="*" element={<div>not found return 404</div>} />
Expand Down
14 changes: 8 additions & 6 deletions src/components/shared/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,13 @@ export default function Navbar() {
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink href="/voter/add" className={navigationMenuTriggerStyle()}>
Register as voter
</NavigationMenuLink>
</NavigationMenuItem>
{state.is_admin ? null : (
<NavigationMenuItem>
<NavigationMenuLink href="/voter/add" className={navigationMenuTriggerStyle()}>
Register as voter
</NavigationMenuLink>
</NavigationMenuItem>
)}
<NavigationMenuItem>
<NavigationMenuLink className={navigationMenuTriggerStyle()} href="/about">
About
Expand All @@ -86,7 +88,7 @@ export default function Navbar() {
<div className="flex items-center gap-4">
{state.is_admin ? (
<Button variant="ghost" size="sm" asChild className="hidden md:flex">
<Link to="/admin" className='font-medium'>
<Link to="/admin/elections" className="font-medium">
<Shield className="h-4 w-4" />
Admin
</Link>
Expand Down
155 changes: 155 additions & 0 deletions src/components/ui/alert-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import * as React from "react"
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"

function AlertDialog({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
}

function AlertDialogTrigger({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
return (
<AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
)
}

function AlertDialogPortal({
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
return (
<AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
)
}

function AlertDialogOverlay({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
return (
<AlertDialogPrimitive.Overlay
data-slot="alert-dialog-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
className
)}
{...props}
/>
)
}

function AlertDialogContent({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) {
return (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
data-slot="alert-dialog-content"
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
className
)}
{...props}
/>
</AlertDialogPortal>
)
}

function AlertDialogHeader({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-header"
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
{...props}
/>
)
}

function AlertDialogFooter({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-dialog-footer"
className={cn(
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
className
)}
{...props}
/>
)
}

function AlertDialogTitle({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
return (
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn("text-lg font-semibold", className)}
{...props}
/>
)
}

function AlertDialogDescription({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
return (
<AlertDialogPrimitive.Description
data-slot="alert-dialog-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
)
}

function AlertDialogAction({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) {
return (
<AlertDialogPrimitive.Action
className={cn(buttonVariants(), className)}
{...props}
/>
)
}

function AlertDialogCancel({
className,
...props
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) {
return (
<AlertDialogPrimitive.Cancel
className={cn(buttonVariants({ variant: "outline" }), className)}
{...props}
/>
)
}

export {
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
}
46 changes: 24 additions & 22 deletions src/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
import * as React from 'react';
import { Slot } from '@radix-ui/react-slot';
import { cva, type VariantProps } from 'class-variance-authority';
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from '@/lib/utils';
import { cn } from "@/lib/utils"

const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-[color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
destructive:
'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
outline:
'border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
icon: 'size-9',
default: "h-9 px-4 py-2 has-[>svg]:px-3",
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
icon: "size-9",
},
},
defaultVariants: {
variant: 'default',
size: 'default',
variant: "default",
size: "default",
},
}
);
)

function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<'button'> &
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean;
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'button';
const Comp = asChild ? Slot : "button"

return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
)
}

Check warning on line 56 in src/components/ui/button.tsx

View workflow job for this annotation

GitHub Actions / Lint, Format, and Build

Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components

export { Button, buttonVariants };
export { Button, buttonVariants }
2 changes: 1 addition & 1 deletion src/pages/CreateElection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export default function CreateElectionPage() {
<Link to="/admin/elections">View All Elections</Link>
</Button>
<Button onClick={() => setSuccessDialogOpen(false)} asChild>
<Link to="/admin/elections/1">View Election Details</Link>
<Link to="/admin/elections/26">View Election Details</Link>
</Button>
</DialogFooter>
</DialogContent>
Expand Down
4 changes: 3 additions & 1 deletion src/pages/election/ElectionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import { Badge } from '@/components/ui/badge';
import { Play, Square } from 'lucide-react';
import { Separator } from '@/components/ui/separator';
import { useNavigate, useParams } from 'react-router';

Check failure on line 7 in src/pages/election/ElectionPage.tsx

View workflow job for this annotation

GitHub Actions / Lint, Format, and Build

Duplicate identifier 'useParams'.
import { useParams } from 'react-router';

Check failure on line 8 in src/pages/election/ElectionPage.tsx

View workflow job for this annotation

GitHub Actions / Lint, Format, and Build

Duplicate identifier 'useParams'.
import AuthContext from '@/context/AuthContext';
import { toast } from 'sonner';

Expand All @@ -27,7 +28,7 @@
const [election, setElection] = React.useState<ElectionProps | null>(null);
const [candidates, setCandidates] = React.useState<CandidateProps[] | null>(null);
const { state } = useContext(AuthContext);

const navigate = useNavigate();
const params = useParams();

const handleStartElection = async () => {
Expand Down Expand Up @@ -79,6 +80,7 @@
loading: 'Ending election...',
success: () => {
setElectionStatus('Ended');
navigate('/admin/results');
return 'Election ended successfully';
},
error: (error) => {
Expand Down
Loading
Loading