import { useEffect, useRef, useState } from "react"; import { useShellStore } from "../app/shellStore"; import { BOSS_TESTING_STATUSES, BOSS_TESTING_STATUS_LABELS, useBossTestingReviews, type BossTestingStatus } from "../app/bossTestingReviews"; import { bossTestIsDefeated } from "../game/BossTestingBridge"; import { enterBossTesting, prepareBossTesting } from "../app/bossTestingRuntime"; import { anotherRandomTestingBoss, BOSS_TESTING_CATALOG } from "../game/bossTesting"; import { useGameStore } from "../game/store"; import { useMenuController, type MenuAction } from "../input/useMenuController"; import { ControllerButton } from "./ControllerButton"; import "./bossTesting.css"; export function BossTestingReviewPanel() { const boss = useGameStore((state) => state.bossTest); const session = useShellStore((state) => state.session); const review = useBossTestingReviews((state) => boss ? state.reviews[boss.key] : undefined); const save = useBossTestingReviews((state) => state.save); const refresh = useBossTestingReviews((state) => state.refresh); const [saving, setSaving] = useState(false); const [startingRandom, setStartingRandom] = useState(false); const [message, setMessage] = useState(""); const busy = useRef(false); const mark = async (status: BossTestingStatus) => { if (!boss || busy.current) return; busy.current = true; setSaving(true); setMessage(""); const synced = await save(boss, status, session); setMessage(synced ? `Marked ${BOSS_TESTING_STATUS_LABELS[status].toLowerCase()}.` : "Saved on this device. This label will sync when you reconnect or reopen Boss Testing."); busy.current = false; setSaving(false); }; useEffect(() => { void refresh(session); const reconnect = () => void refresh(session); window.addEventListener("online", reconnect); return () => window.removeEventListener("online", reconnect); }, [refresh, session]); const defeated = bossTestIsDefeated(); const disabled = saving || startingRandom; const back = () => { if (!busy.current) useGameStore.getState().openOverlay("pause"); }; const retry = () => useGameStore.getState().resetAtEntrance(); const leave = () => useShellStore.getState().returnToMainMenu(); const fightRandom = async () => { if (busy.current || !boss) return; const next = anotherRandomTestingBoss(BOSS_TESTING_CATALOG, boss.key); if (!next) { setMessage("No other bosses are available."); return; } busy.current = true; setStartingRandom(true); setMessage(`Preparing ${next.name}…`); try { await prepareBossTesting(next); enterBossTesting(next, useShellStore.getState().activeDungeonRole ?? undefined); } catch (failure) { setMessage(failure instanceof Error ? failure.message : "The next boss could not be started. Please retry."); } finally { busy.current = false; setStartingRandom(false); } }; const actions: MenuAction[] = [ ...BOSS_TESTING_STATUSES.map((status) => ({ id: `boss-review-${status}`, run: () => void mark(status), enabled: !disabled })), { id: "boss-review-report", run: () => useGameStore.getState().openOverlay("report-issue"), enabled: !disabled }, { id: "boss-review-retry", run: retry, enabled: !disabled }, { id: "boss-review-random", run: () => void fightRandom(), enabled: !disabled }, { id: "boss-review-leave", run: leave, enabled: !disabled }, { id: "boss-review-back", run: back, enabled: !disabled }, ]; const controller = useMenuController(actions, { initialId: "boss-review-needs-testing", onBack: back }); if (!boss) return null; const button = (controlId: string, label: string, run: () => void, pressed?: boolean) => {label}; return

{defeated ? "Boss defeated" : "Boss Testing paused"}

{boss.name}

Current readiness: {BOSS_TESTING_STATUS_LABELS[review?.status ?? "needs-testing"]}

{BOSS_TESTING_STATUSES.map((status) => {button(`boss-review-${status}`, `Mark ${BOSS_TESTING_STATUS_LABELS[status].toLowerCase()}`, () => void mark(status), review?.status === status)} )}
{message &&

{message}

}
{button("boss-review-report", "Submit a boss report", () => useGameStore.getState().openOverlay("report-issue"))} {button("boss-review-retry", "Fight this boss again", retry)} {button("boss-review-random", startingRandom ? "Preparing random boss…" : "Fight another random boss", () => void fightRandom())} {button("boss-review-leave", "Return to main menu", leave)} {button("boss-review-back", "Back to pause menu", back)}
; }