"use client"; import { useEffect, useState, useCallback, useRef } from "react"; import { createPortal } from "react-dom"; import Link from "next/link"; import Image from "next/image"; import { FiUsers, FiArrowLeft, FiShield, FiUser, FiLoader, FiChevronDown, FiCalendar, FiHash, FiUserCheck, FiUserX, } from "react-icons/fi"; import { MdAdminPanelSettings } from "react-icons/md"; import "../styles/AdminDashboard.css"; import "./AdminUsers.css"; const PAGE_LIMIT = 12; function RoleBadge({ role }) { if (role === "superadmin") return Super Admin; if (role === "admin") return Admin; return User; } function formatDate(dateStr) { if (!dateStr) return "—"; return new Date(dateStr).toLocaleDateString("en-IN", { day: "2-digit", month: "short", year: "numeric", }); } export default function AdminUsers() { const [myRole, setMyRole] = useState(null); const [token, setToken] = useState(""); const [myUsn, setMyUsn] = useState(""); const [isLoaded, setIsLoaded] = useState(false); const [users, setUsers] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [loading, setLoading] = useState(false); const [loadingMore, setLoadingMore] = useState(false); const [error, setError] = useState(""); const [changingRole, setChangingRole] = useState({}); const [roleMsg, setRoleMsg] = useState({}); const [openConfirmUsn, setOpenConfirmUsn] = useState(null); const [confirmAction, setConfirmAction] = useState(null); const [dropdownPos, setDropdownPos] = useState({ top: 0, left: 0 }); const confirmRef = useRef(null); const btnRefs = useRef({}); // ── bootstrap ── useEffect(() => { const r = localStorage.getItem("role") || ""; const t = localStorage.getItem("token") || ""; const u = localStorage.getItem("usn") || ""; setMyRole(r); setToken(t); setMyUsn(u); setTimeout(() => setIsLoaded(true), 100); }, []); // ── fetch users ── const fetchUsers = useCallback(async (pageNum, append = false) => { if (!token) return; append ? setLoadingMore(true) : setLoading(true); setError(""); try { const res = await fetch(`/api/admin/users?page=${pageNum}&limit=${PAGE_LIMIT}`, { headers: { Authorization: `Bearer ${token}` }, }); const data = await res.json(); if (!res.ok) { setError(data.error || "Failed to fetch users"); return; } append ? setUsers(prev => [...prev, ...data.users]) : setUsers(data.users); setTotal(data.total); setPage(data.page); setTotalPages(data.totalPages); } catch { setError("Network error. Please try again."); } finally { setLoading(false); setLoadingMore(false); } }, [token]); useEffect(() => { if (token && (myRole === "admin" || myRole === "superadmin")) fetchUsers(1, false); }, [token, myRole, fetchUsers]); const handleViewMore = () => fetchUsers(page + 1, true); // ── inline confirm helpers ── const openConfirm = (user, newRole, usn) => { const btn = btnRefs.current[usn]; if (btn) { const rect = btn.getBoundingClientRect(); const dropH = 190; const dropW = 230; const spaceBelow = window.innerHeight - rect.bottom; const top = spaceBelow > dropH ? rect.bottom + 8 : rect.top - dropH - 8; const spaceRight = window.innerWidth - rect.left; const left = spaceRight > dropW ? rect.left : rect.right - dropW; setDropdownPos({ top, left }); } setOpenConfirmUsn(user.usn); setConfirmAction({ user, newRole }); }; const closeConfirm = () => { setOpenConfirmUsn(null); setConfirmAction(null); }; const handleConfirmed = () => { if (!confirmAction) return; handleRoleChange(confirmAction.user, confirmAction.newRole); closeConfirm(); }; // close on outside click useEffect(() => { if (!openConfirmUsn) return; const handler = (e) => { if (confirmRef.current && !confirmRef.current.contains(e.target)) { const btns = Object.values(btnRefs.current); if (btns.some(b => b && b.contains(e.target))) return; closeConfirm(); } }; document.addEventListener("mousedown", handler); return () => document.removeEventListener("mousedown", handler); }, [openConfirmUsn]); // ── change role ── const handleRoleChange = async (user, newRole) => { setChangingRole(prev => ({ ...prev, [user.usn]: true })); setRoleMsg(prev => ({ ...prev, [user.usn]: "" })); try { const res = await fetch("/api/admin/users/role", { method: "PATCH", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` }, body: JSON.stringify({ targetUsn: user.usn, newRole }), }); const data = await res.json(); if (!res.ok) { setRoleMsg(prev => ({ ...prev, [user.usn]: data.error || "Failed" })); return; } setUsers(prev => prev.map(u => u.usn === user.usn ? { ...u, role: data.user.role } : u)); setRoleMsg(prev => ({ ...prev, [user.usn]: newRole === "admin" ? "Made admin ✓" : "Removed admin ✓", })); setTimeout(() => setRoleMsg(prev => ({ ...prev, [user.usn]: "" })), 2500); } catch { setRoleMsg(prev => ({ ...prev, [user.usn]: "Network error" })); } finally { setChangingRole(prev => ({ ...prev, [user.usn]: false })); } }; // ── guards ── if (myRole === null) return null; const isSuperAdmin = myRole === "superadmin"; return (
{/* ── Header ── */}
Admin Dashboard
User Management

All Users

Latest registered users — {total > 0 ? `${total} total` : "loading…"}

{/* ── Summary strip ── */}
{total}
Total Users
{users.filter(u => (u.role || "user") === "admin").length}
Admins (loaded)
{users.filter(u => !u.role || u.role === "user").length}
Regular Users
{users.length}
Loaded
{/* ── Error ── */} {error &&
{error}
} {/* ── User list ── */} {loading ? (

Loading users…

) : ( <>
{users.map((user, idx) => { const userRole = user.role || "user"; const isChanging = changingRole[user.usn]; const msg = roleMsg[user.usn]; const isOwnAccount = user.usn === myUsn; const isOpen = openConfirmUsn === user.usn; return (
{/* Avatar + name row */}
{user.name}

{user.name}

{user.usn}

{/* Meta row */}
Joined {formatDate(user.createdAt)}
{/* Role action — superadmin only, not own account */} {isSuperAdmin && !isOwnAccount && (
{userRole === "admin" ? ( ) : ( )}
{msg && {msg}}
)} {/* Own account label */} {isOwnAccount &&
You
}
); })}
{/* ── View more ── */} {page < totalPages && (
)} {users.length > 0 && page >= totalPages && (

All {total} users loaded

)} {users.length === 0 && !loading && (

No users found

)} )} {/* ── Portal confirm dropdown ── renders on document.body, floats above everything ── */} {openConfirmUsn && confirmAction && typeof document !== "undefined" && createPortal(
{confirmAction.newRole === "admin" ? : }

{confirmAction.newRole === "admin" ? "Make Admin?" : "Remove Admin?"}

{confirmAction.newRole === "admin" ? <>{confirmAction.user.name} will gain admin access. : <>{confirmAction.user.name} will lose admin access.}

, document.body ) }
); }