diff --git a/apps/web/app/dashboard/users/page.tsx b/apps/web/app/dashboard/users/page.tsx index 96ace06..cceb9d1 100644 --- a/apps/web/app/dashboard/users/page.tsx +++ b/apps/web/app/dashboard/users/page.tsx @@ -1,10 +1,15 @@ "use client"; -import { Ban, CheckCircle, Edit, Trash2 } from "lucide-react"; +import { Ban, CheckCircle, Edit, ShieldCheck, Trash2, UserRoundCheck, Users } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; +import { ConfirmDialog } from "@/components/confirm-dialog"; +import { DataTable, type DataTableColumn } from "@/components/data-table"; +import { PageHeader, PageShell, StatePanel } from "@/components/page-layout"; +import { SectionCard, TableActions } from "@/components/section-card"; +import { StatStrip } from "@/components/stat-strip"; +import { StatusBadge } from "@/components/status-badge"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, DialogContent, @@ -22,14 +27,6 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; import { api } from "@/lib/api-client"; import { getUserApi } from "@/lib/api-helpers"; import { useSession } from "@/lib/auth-client"; @@ -39,10 +36,10 @@ type User = { name: string; email: string; role: string; - createdAt: string; + createdAt: Date; emailVerified: boolean; isSuspended: boolean; - suspendedUntil: string | null; + suspendedUntil: Date | null; }; export default function UsersPage() { @@ -55,9 +52,9 @@ export default function UsersPage() { const fetchUsers = useCallback(async () => { try { - const { data } = await api.api.users.get(); - if (data && typeof data === "object" && "users" in data) { - setUsers(data.users as User[]); + const { data, error } = await api.api.users.get(); + if (!error && data) { + setUsers(data); } } catch (_error) { } finally { @@ -144,104 +141,128 @@ export default function UsersPage() { return true; }; - if (loading) { - return ( -
-
Loading...
-
- ); - } + const columns: readonly DataTableColumn[] = [ + { id: "name", header: "Name", cell: (user) => user.name, className: "font-bold" }, + { + id: "email", + header: "Email", + cell: (user) => user.email, + className: "font-mono text-xs text-muted-foreground", + }, + { + id: "role", + header: "Role", + cell: (user) => ( + {user.role} + ), + }, + { + id: "status", + header: "Status", + cell: (user) => + isUserSuspended(user) ? ( + + Suspended + {user.suspendedUntil && ` until ${new Date(user.suspendedUntil).toLocaleDateString()}`} + + ) : ( + + {user.emailVerified ? "Active" : "Unverified"} + + ), + }, + { + id: "created", + header: "Created", + cell: (user) => new Date(user.createdAt).toLocaleDateString(), + className: "text-muted-foreground", + }, + { + id: "actions", + header: "Actions", + headerClassName: "text-right", + className: "text-right", + cell: (user) => ( + + + {isUserSuspended(user) ? ( + + ) : ( + + )} + + + ), + }, + ]; return ( -
-
-

User Management

-

Manage user accounts and permissions

-
+ + user.role === "admin").length, + icon: ShieldCheck, + }, + { + label: "Active", + value: users.filter((user) => !isUserSuspended(user)).length, + icon: UserRoundCheck, + tone: "positive", + }, + ]} + /> + ) + } + /> - - - Users - All registered users in the system - - -
- - - - Name - Email - Role - Status - Created - Actions - - - - {users.map((user) => ( - - {user.name} - {user.email} - - - {user.role} - - - -
- {isUserSuspended(user) ? ( - - Suspended - {user.suspendedUntil && - ` until ${new Date(user.suspendedUntil).toLocaleDateString()}`} - - ) : ( - - {user.emailVerified ? "Active" : "Unverified"} - - )} -
-
- {new Date(user.createdAt).toLocaleDateString()} - -
- - {isUserSuspended(user) ? ( - - ) : ( - - )} - -
-
-
- ))} -
-
-
-
-
+ {loading ? ( + + ) : ( + + user.id} /> + + )} setEditingUser(null)}> @@ -313,24 +334,16 @@ export default function UsersPage() { - setDeleteUser(null)}> - - - Delete User - - Are you sure you want to delete {deleteUser?.name}? This action cannot be undone. - - - - - - - - -
+ Are you sure you want to delete {deleteUser?.name}? This action cannot be undone. + } + confirmLabel="Delete" + onConfirm={handleDelete} + onOpenChange={(open) => !open && setDeleteUser(null)} + /> + ); }