From 5b115ae9ffa57f82a61f2a505e9521855295a77f Mon Sep 17 00:00:00 2001 From: Ace Date: Thu, 18 Jun 2026 15:45:59 +0200 Subject: [PATCH] SuperAdmin changes --- src/app/(dashboard)/users/page.tsx | 109 ++++++++++++---------- src/app/api/users/[id]/route.ts | 24 +++++ src/app/api/users/route.ts | 78 ++++++++++++++++ src/app/page.tsx | 2 +- src/components/users/user-form-dialog.tsx | 77 +++++++++------ src/components/users/users-table.tsx | 38 +++++--- 6 files changed, 239 insertions(+), 89 deletions(-) create mode 100644 src/app/api/users/[id]/route.ts create mode 100644 src/app/api/users/route.ts diff --git a/src/app/(dashboard)/users/page.tsx b/src/app/(dashboard)/users/page.tsx index 48cf43f..be937a7 100644 --- a/src/app/(dashboard)/users/page.tsx +++ b/src/app/(dashboard)/users/page.tsx @@ -1,22 +1,54 @@ "use client" -import { useState } from "react" +import { useState, useEffect, useCallback } from "react" import { PageHeader } from "@/components/shared/page-header" import { UsersTable } from "@/components/users/users-table" import { UserFormDialog } from "@/components/users/user-form-dialog" import { Button } from "@/components/ui/button" -import { users } from "@/data/users" -import { Plus, Users as UsersIcon } from "lucide-react" +import { Input } from "@/components/ui/input" +import { Plus, Search, Users as UsersIcon } from "lucide-react" +import { User } from "@/types" +import { toast } from "sonner" export default function UsersPage() { const [createOpen, setCreateOpen] = useState(false) + const [users, setUsers] = useState([]) + const [loading, setLoading] = useState(true) + const [searchQuery, setSearchQuery] = useState("") + + const fetchUsers = useCallback(async () => { + try { + const res = await fetch("/api/users") + const data = await res.json() + if (data.users) setUsers(data.users) + } catch { + toast.error("Failed to load users") + } finally { + setLoading(false) + } + }, []) + + useEffect(() => { + fetchUsers() + }, [fetchUsers]) + + const filteredUsers = searchQuery.trim() + ? users.filter((u) => + u.name.toLowerCase().includes(searchQuery.toLowerCase()) || + u.email.toLowerCase().includes(searchQuery.toLowerCase()) + ) + : users + + const stats = [ + { label: "Total Users", value: users.length, color: "bg-blue-500/10", textColor: "text-blue-600 dark:text-blue-400" }, + { label: "Active", value: users.filter((u) => u.active).length, color: "bg-emerald-500/10", textColor: "text-emerald-600 dark:text-emerald-400" }, + { label: "Admins", value: users.filter((u) => u.role === "admin" || u.role === "super_admin").length, color: "bg-purple-500/10", textColor: "text-purple-600 dark:text-purple-400" }, + { label: "Sales", value: users.filter((u) => u.role === "sales_user").length, color: "bg-amber-500/10", textColor: "text-amber-600 dark:text-amber-400" }, + ] return (
- + - diff --git a/src/components/users/users-table.tsx b/src/components/users/users-table.tsx index d597e6b..0c25783 100644 --- a/src/components/users/users-table.tsx +++ b/src/components/users/users-table.tsx @@ -11,17 +11,31 @@ import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" import { User } from "@/types" -import { Pencil, Power, PowerOff } from "lucide-react" +import { Pencil, Trash2 } from "lucide-react" +import { toast } from "sonner" interface UsersTableProps { data: User[] loading?: boolean + onUserDeleted?: () => void } -export function UsersTable({ data, loading }: UsersTableProps) { +export function UsersTable({ data, loading, onUserDeleted }: UsersTableProps) { const [editingUser, setEditingUser] = useState(null) const [editOpen, setEditOpen] = useState(false) + const handleDelete = async (id: string) => { + if (!confirm("Are you sure you want to delete this user?")) return + try { + const res = await fetch(`/api/users/${id}`, { method: "DELETE" }) + if (!res.ok) throw new Error() + toast.success("User deleted") + onUserDeleted?.() + } catch { + toast.error("Failed to delete user") + } + } + const columns: ColumnDef[] = useMemo( () => [ { @@ -76,15 +90,15 @@ export function UsersTable({ data, loading }: UsersTableProps) { ), cell: ({ row }) => { const role = row.getValue("role") as string + const colors: Record = { + super_admin: "bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20", + admin: "bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20", + sales_user: "bg-purple-500/10 text-purple-600 dark:text-purple-400 border-purple-500/20", + developer: "bg-zinc-500/10 text-zinc-600 dark:text-zinc-400 border-zinc-500/20", + } return ( - - {role} + + {role.replace("_", " ")} ) }, @@ -117,8 +131,9 @@ export function UsersTable({ data, loading }: UsersTableProps) { variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-destructive" + onClick={() => handleDelete(user.id)} > - {user.active ? : } +
) @@ -140,6 +155,7 @@ export function UsersTable({ data, loading }: UsersTableProps) { open={editOpen} onOpenChange={setEditOpen} user={editingUser} + onUserCreated={onUserDeleted} /> )