const token = localStorage.getItem("indiko_session"); const footer = document.getElementById("footer") as HTMLElement; const usersList = document.getElementById("usersList") as HTMLElement; let currentUserId: number; // Check auth and display user async function checkAuth() { if (!token) { window.location.href = "/login"; return; } try { const response = await fetch("/api/hello", { headers: { Authorization: `Bearer ${token}`, }, }); if (response.status === 401 || response.status === 403) { localStorage.removeItem("indiko_session"); window.location.href = "/login"; return; } const data = await response.json(); currentUserId = data.id; footer.innerHTML = `admin • signed in as ${data.username}sign out `; // Handle logout document .getElementById("logoutLink") ?.addEventListener("click", async (e) => { e.preventDefault(); try { await fetch("/auth/logout", { method: "POST", headers: { Authorization: `Bearer ${token}`, }, }); } catch { // Ignore logout errors } localStorage.removeItem("indiko_session"); window.location.href = "/login"; }); // Check if admin if (!data.isAdmin) { window.location.href = "/"; return; } // Load users if admin loadUsers(); } catch (error) { console.error("Auth check failed:", error); footer.textContent = "error loading user info"; usersList.innerHTML = '
Failed to load users
'; } } async function loadUsers() { try { const response = await fetch("/api/users", { headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { throw new Error("Failed to load users"); } const data = await response.json(); if (data.users.length === 0) { usersList.innerHTML = '
No users found
'; return; } usersList.innerHTML = data.users .map( (user: { id: number; username: string; name: string; email: string | null; photo: string | null; status: string; role: string; isAdmin: boolean; createdAt: number; credentialCount: number; }) => { const createdDate = new Date( user.createdAt * 1000, ).toLocaleDateString(); const initials = user.username.substring(0, 2).toUpperCase(); const avatarContent = user.photo ? `${user.username}` : initials; const isSelf = user.id === currentUserId; return `
${avatarContent}
${user.username}${isSelf ? " (you)" : ""}
${user.credentialCount} passkey${user.credentialCount !== 1 ? "s" : ""} joined ${createdDate} ${user.email ? `${user.email}` : ""}
${user.status} ${user.role}
${ !isSelf ? user.status === "suspended" ? `` : `` : "" } ${!isSelf ? `` : ""}
`; }, ) .join(""); // Add event listeners for action buttons document.querySelectorAll("button[data-action]").forEach((btn) => { btn.addEventListener("click", handleUserAction); }); } catch (error) { console.error("Failed to load users:", error); usersList.innerHTML = '
Failed to load users
'; } } async function handleUserAction(e: Event) { const btn = e.target as HTMLButtonElement; const action = btn.dataset.action; const userId = btn.dataset.userId; if (!userId || !action) return; // Check if already in confirmation state if (btn.dataset.confirmState === "pending") { // Second click - perform action btn.dataset.confirmState = ""; btn.disabled = true; try { let endpoint = ""; let method = "POST"; if (action === "delete") { endpoint = `/api/admin/users/${userId}/delete`; method = "DELETE"; } else if (action === "disable") { endpoint = `/api/admin/users/${userId}/disable`; } else if (action === "enable") { endpoint = `/api/admin/users/${userId}/enable`; } const response = await fetch(endpoint, { method, headers: { Authorization: `Bearer ${token}`, }, }); if (!response.ok) { const error = await response.json(); throw new Error(error.error || "Failed to perform action"); } // Reload users list loadUsers(); } catch (error) { console.error(`Failed to ${action} user:`, error); alert( `Failed to ${action} user: ${error instanceof Error ? error.message : "Unknown error"}`, ); btn.disabled = false; } } else { // First click - set confirmation state const originalText = btn.textContent; btn.dataset.confirmState = "pending"; btn.dataset.originalText = originalText || ""; btn.textContent = "you sure?"; // Reset after 3 seconds if not clicked again setTimeout(() => { if (btn.dataset.confirmState === "pending") { btn.dataset.confirmState = ""; btn.textContent = btn.dataset.originalText || originalText; } }, 3000); } } checkAuth();