"use client"; import { useEffect, useState } from "react"; import { useAuth } from "@/context/AuthContext"; // adjust path if needed import { Loader2 } from "lucide-react"; import type { AdminUser, UserRole } from "@/types/user"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? ""; export default function AdminUsersPage() { const { getAuthHeaders } = useAuth(); const [users, setUsers] = useState([]); const [loading, setLoading] = useState(true); const [savingId, setSavingId] = useState(null); const [error, setError] = useState(null); async function fetchUsers() { console.log("in the users fetch"); try { setLoading(true); setError(null); const res = await fetch(`/api/admin/users`, { headers: { ...getAuthHeaders(), }, }); if (!res.ok) { throw new Error(`Failed to load users (${res.status})`); } const data: AdminUser[] = await res.json(); setUsers(data); } catch (err: any) { console.error(err); setError(err.message ?? "Failed to load users"); } finally { setLoading(false); } } useEffect(() => { fetchUsers(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); async function handleRoleChange(userId: string, newRole: UserRole) { setSavingId(userId); setError(null); const prev = users; setUsers((cur) => cur.map((u) => (u.id === userId ? { ...u, role: newRole } : u)) ); try { const res = await fetch(`${API_BASE_URL}/admin/users/${userId}/role`, { method: "PATCH", headers: { "Content-Type": "application/json", ...getAuthHeaders(), }, body: JSON.stringify({ role: newRole }), }); if (!res.ok) { throw new Error(`Failed to update role (${res.status})`); } } catch (err: any) { console.error(err); setError(err.message ?? "Failed to update role"); // rollback setUsers(prev); } finally { setSavingId(null); } } function handleRoleSelectChange(user: AdminUser, newRole: UserRole) { if (newRole === user.role) { return; } // Confirm promotions to ADMIN if ( newRole === "ADMIN" && !window.confirm( `Promote ${user.email} to ADMIN? This will give them access to the admin console.` ) ) { return; } // Confirm demotions from ADMIN if ( user.role === "ADMIN" && newRole === "USER" && !window.confirm( `Remove ADMIN access from ${user.email}? They will lose access to the admin console.` ) ) { return; } void handleRoleChange(user.id, newRole); } return (

Users & Roles

Promote trusted accounts to admins. All new signups start as{" "} USER.

{error && (
{error}
)} {loading ? (
Loading users…
) : users.length === 0 ? (
No users found yet. Once people start signing up, they'll show up here.
) : (
{users.map((u, idx) => ( ))}
Email Display Name Role Created Last Login
{u.email} {u.displayName || "—"}
{u.role}
{u.createdAt ? new Date(u.createdAt).toLocaleDateString() : "—"} {u.lastLoginAt ? new Date(u.lastLoginAt).toLocaleDateString() : "—"}
)}

Note: Role changes take effect on the user's next request. All new accounts are created as USER by default.

); }