27 lines
2.6 KiB
TypeScript
27 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { ShieldCheck, UserRound } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
type AdminUser = { id: string; name: string; email: string; role: "admin" | "member"; isCurrent: boolean };
|
|
|
|
export function AdminUsers({ initialUsers }: { initialUsers: AdminUser[] }) {
|
|
const [users, setUsers] = useState(initialUsers); const [message, setMessage] = useState(""); const [pendingId, setPendingId] = useState("");
|
|
async function changeRole(user: AdminUser) {
|
|
const role = user.role === "admin" ? "member" : "admin";
|
|
setPendingId(user.id); setMessage("");
|
|
try {
|
|
const response = await fetch(`/api/admin/users/${user.id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ role }) });
|
|
const result = await response.json();
|
|
if (!response.ok) { setMessage(result.error); return; }
|
|
setUsers(users.map((entry) => entry.id === user.id ? { ...entry, role } : entry));
|
|
setMessage(`${user.name} is now ${role === "admin" ? "an administrator" : "a member"}.`);
|
|
} catch {
|
|
setMessage("The role could not be changed. Try again.");
|
|
} finally {
|
|
setPendingId("");
|
|
}
|
|
}
|
|
return <section className="mt-8 rounded-[1.75rem] bg-white p-6 card-shadow sm:p-8"><div><h2 className="font-warm text-2xl font-bold text-[var(--brand)]">Registered accounts</h2><p className="mt-1 text-sm text-[#697570]">Administrators can edit every family and manage organization branding.</p></div><div className="mt-6 divide-y divide-black/6">{users.map((user) => <div key={user.id} className="flex flex-wrap items-center gap-4 py-4"><span className={`grid size-11 place-items-center rounded-xl ${user.role === "admin" ? "bg-[var(--brand)] text-white" : "bg-[var(--surface)] text-[var(--brand)]"}`}>{user.role === "admin" ? <ShieldCheck size={20}/> : <UserRound size={20}/>}</span><div className="mr-auto min-w-0"><p className="font-bold">{user.name}{user.isCurrent && <span className="ml-2 text-xs font-normal text-[#697570]">You</span>}</p><p className="truncate text-sm text-[#697570]">{user.email}</p></div><span className="rounded-full bg-[var(--surface)] px-3 py-1 text-xs font-bold uppercase tracking-wider text-[var(--brand)]">{user.role}</span>{!user.isCurrent && <button type="button" disabled={pendingId === user.id} onClick={() => changeRole(user)} className="btn-secondary text-sm">{pendingId === user.id ? "Saving..." : user.role === "admin" ? "Make member" : "Make admin"}</button>}</div>)}</div>{message && <p className="mt-4 rounded-xl bg-[var(--surface)] p-3 text-sm font-medium">{message}</p>}</section>;
|
|
}
|