import { adminApi } from "./api.js"; import { t } from "./i18n.js"; import { state } from "./state.js"; import { $, toast } from "./dom.js"; import { openPasswordConfirmModal, openResultsRelockModal, renderPhasePill, } from "./ui.js"; async function adminAction(fn, successMessage, runSerializedRefresh) { try { await fn(); toast(successMessage); await runSerializedRefresh(); return true; } catch (err) { toast(err.message, true); return false; } } function setupAdminPanelToggle() { const adminToggle = $("admin-toggle"); const adminCard = $("admin-card"); const adminClose = $("admin-close"); if (!adminToggle || !adminCard || !adminClose) return; const togglePanel = (show) => adminCard.classList.toggle("hidden", !show); adminToggle.addEventListener("click", () => togglePanel(adminCard.classList.contains("hidden")), ); adminClose.addEventListener("click", () => togglePanel(false)); } function setupResetButtons(runSerializedRefresh) { const askPasswordThenRun = ({ title, body, confirmLabel, action, done, }) => { openPasswordConfirmModal({ title, body, confirmLabel, onConfirm: async (password, close) => { const success = await adminAction( () => action(password), done, runSerializedRefresh, ); if (success) close(); }, }); }; $("reset").addEventListener("click", () => askPasswordThenRun({ title: t("admin.reset"), body: t("admin.resetConfirmBody"), confirmLabel: t("admin.reset"), action: (password) => adminApi.reset(password), done: t("admin.resetDone"), }), ); $("factory-reset").addEventListener("click", () => askPasswordThenRun({ title: t("admin.factoryReset"), body: t("admin.factoryResetConfirmBody"), confirmLabel: t("admin.factoryReset"), action: (password) => adminApi.factoryReset(password), done: t("admin.factoryResetDone"), }), ); } function setupResultsToggle(runSerializedRefresh) { const resultsToggle = $("results-open-toggle"); if (!resultsToggle) return; resultsToggle.addEventListener("click", async () => { const desired = !state.resultsOpen; resultsToggle.disabled = true; try { const resp = await adminApi.setResultsOpen(desired); const wasResultsOpen = state.resultsOpen; const wasPhase = state.phase; state.resultsOpen = resp.resultsOpen; if (wasResultsOpen && !resp.resultsOpen && wasPhase === "Results") { openResultsRelockModal(); } renderPhasePill(); toast(t("admin.resultsUpdated")); await runSerializedRefresh(); } catch (err) { toast(err.message, true); } finally { resultsToggle.disabled = false; } }); } function setupLinkApply(runSerializedRefresh) { const linkApply = $("link-apply"); if (!linkApply) return; linkApply.addEventListener("click", async () => { const source = Number($("link-source")?.value); const target = Number($("link-target")?.value); if (!source || !target || source === target) { return toast(t("admin.linkValidation"), true); } try { await adminApi.linkSuggestions(source, target); toast(t("admin.linkDone")); await runSerializedRefresh(); } catch (err) { toast(err.message, true); } }); } function setupPlayerTableActions(runSerializedRefresh) { const playerTable = $("admin-player-table"); if (!playerTable) return; const syncSelectFocusState = () => { state.adminStatusMenuOpen = !!playerTable.querySelector( ".admin-status-select:focus", ); }; playerTable.addEventListener("focusin", (e) => { if (e.target.closest(".admin-status-select")) { state.adminStatusMenuOpen = true; } }); playerTable.addEventListener("focusout", () => { window.setTimeout(syncSelectFocusState, 0); }); playerTable.addEventListener("change", async (e) => { const statusSelect = e.target.closest(".admin-status-select"); if (!statusSelect || statusSelect.disabled) return; const playerId = statusSelect.dataset.playerPhase; const currentPhase = statusSelect.dataset.currentPhase; const desiredPhase = statusSelect.value; if (!playerId || !desiredPhase || desiredPhase === currentPhase) return; statusSelect.disabled = true; try { await adminApi.setPlayerPhase(playerId, desiredPhase); toast(t("admin.statusUpdated")); await runSerializedRefresh(); } catch (err) { statusSelect.value = currentPhase ?? statusSelect.value; toast(err.message, true); } finally { statusSelect.disabled = false; state.adminStatusMenuOpen = false; } }); playerTable.addEventListener("click", async (e) => { const grantBtn = e.target.closest("[data-grant-joker]"); const deleteBtn = e.target.closest("[data-delete-player]"); if (grantBtn) { const playerId = grantBtn.dataset.grantJoker; try { await adminApi.grantJoker(playerId); toast(t("admin.jokerGranted")); await runSerializedRefresh(); } catch (err) { toast(err.message, true); } } else if (deleteBtn) { const playerId = deleteBtn.dataset.deletePlayer; const name = deleteBtn.dataset.name || ""; openPasswordConfirmModal({ title: t("admin.deleteTitle"), body: t("admin.deleteBody", { name }), confirmLabel: t("admin.deleteConfirm"), onConfirm: async (password, close) => { try { await adminApi.deletePlayer(playerId, password); toast(t("admin.deleteDone")); close(); await runSerializedRefresh(); } catch (err) { toast(err.message, true); } }, }); } }); } export function setupAdminHandlers({ runSerializedRefresh }) { setupResetButtons(runSerializedRefresh); setupAdminPanelToggle(); setupResultsToggle(runSerializedRefresh); setupLinkApply(runSerializedRefresh); setupPlayerTableActions(runSerializedRefresh); }