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 (
-
- );
- }
+ 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} />
+
+ )}
-
-
+ Are you sure you want to delete {deleteUser?.name}? This action cannot be undone.>
+ }
+ confirmLabel="Delete"
+ onConfirm={handleDelete}
+ onOpenChange={(open) => !open && setDeleteUser(null)}
+ />
+
);
}