forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
8a98797fcf
commit
11934a3979
44 files changed
+3183
-329
No files matched your search
@@ -7,6 +7,7 @@ import { type RaceBotSource, type RaceBotTier } from "../app/dungeonRaceBot";
|
||||
import { dungeonsByCategory, randomizedBiteSizedDungeons } from "../game/dungeonCatalog";
|
||||
import { dungeonEnabledForQueue } from "../game/dungeonQueuePolicy";
|
||||
import { formatDungeonDuration } from "../game/dungeonRunTypes";
|
||||
import { dungeonLeaderboardCatalog as leaderboardCatalog } from "../game/dungeonLeaderboardCatalog";
|
||||
import { partyRolesForClass, PARTY_ROLE_LABELS, type PartyRole } from "../game/partyStore";
|
||||
import { specializationById } from "../game/specializationCatalog";
|
||||
import { BrandMark, FrontSurface } from "./FrontSurface";
|
||||
@@ -31,6 +32,7 @@ export function DungeonRaceScreen({ onClose }: { readonly onClose: () => void })
|
||||
const [period, setPeriod] = useState<"30d" | "all">("30d");
|
||||
const [boardScope, setBoardScope] = useState<"overall" | "dungeon">("overall");
|
||||
const [boardView, setBoardView] = useState<"wins" | "times">("wins");
|
||||
const [boardBossId, setBoardBossId] = useState("");
|
||||
const [board, setBoard] = useState<BoardResponse | null>(null);
|
||||
const [boardError, setBoardError] = useState("");
|
||||
useEffect(() => { void refreshPolicy(session); }, [refreshPolicy, session]);
|
||||
@@ -38,17 +40,22 @@ export function DungeonRaceScreen({ onClose }: { readonly onClose: () => void })
|
||||
: dungeonsByCategory("bite-sized")).filter((entry) => entry.available && dungeonEnabledForQueue(policy, entry)),
|
||||
[pool, policy]);
|
||||
const boardDungeonId = dungeonId || allEntries[0]?.id || "";
|
||||
const boardDungeon = leaderboardCatalog.dungeons.find((entry) => entry.id === boardDungeonId);
|
||||
const bossOptions = boardDungeon?.difficulties.find((entry) => entry.id === boardDungeon.defaultDifficultyId)
|
||||
?.finalBossIds?.map((id) => boardDungeon.bosses.find((boss) => boss.id === id)!) ?? [];
|
||||
const selectedBoardBossId = bossOptions.find((boss) => boss.id === boardBossId)?.id ?? bossOptions[0]?.id;
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
const query = new URLSearchParams({ view: boardScope === "overall" ? "wins" : boardView,
|
||||
period, ...(boardScope === "dungeon" && boardDungeonId ? { dungeon: boardDungeonId } : {}) });
|
||||
period, ...(boardScope === "dungeon" && boardDungeonId ? { dungeon: boardDungeonId,
|
||||
...(selectedBoardBossId ? { boss: selectedBoardBossId } : {}) } : {}) });
|
||||
if (boardScope === "dungeon" && !boardDungeonId) { setBoard(null); return; }
|
||||
void requestOnlineJson<BoardResponse>(`/api/dungeon-races/leaderboard?${query}`, { signal: controller.signal })
|
||||
.then((value) => { setBoard(value); setBoardError(""); })
|
||||
.catch((error: unknown) => { if (!controller.signal.aborted) { setBoard(null);
|
||||
setBoardError(error instanceof Error ? error.message : "Leaderboard unavailable."); } });
|
||||
return () => controller.abort();
|
||||
}, [boardDungeonId, boardScope, boardView, period]);
|
||||
}, [boardDungeonId, boardScope, boardView, period, selectedBoardBossId]);
|
||||
const specialization = specializationById(character?.specializationId);
|
||||
const roles = character?.categoryId === "rom" ? partyRolesForClass(character.classId)
|
||||
: specialization ? [specialization.role] : [];
|
||||
@@ -80,8 +87,8 @@ export function DungeonRaceScreen({ onClose }: { readonly onClose: () => void })
|
||||
<button className="front-button" type="button" aria-pressed={pool === "randomized"} disabled={busy}
|
||||
onClick={() => { setPool("randomized"); setDungeonId(""); }}>Randomized Bite-Sized</button>
|
||||
</div>
|
||||
<label>Dungeon<select value={dungeonId} disabled={busy} onChange={(event) => setDungeonId(event.target.value)}>
|
||||
<option value="">Random eligible dungeon</option>
|
||||
<label>{pool === "randomized" ? "Creature pool" : "Dungeon"}<select value={dungeonId} disabled={busy} onChange={(event) => setDungeonId(event.target.value)}>
|
||||
<option value="">{pool === "randomized" ? "Random available creature pool" : "Random eligible dungeon"}</option>
|
||||
{allEntries.map((entry) => <option key={entry.id} value={entry.id}>{entry.title}</option>)}
|
||||
</select></label>
|
||||
<div className="dungeon-race-screen__choices" role="group" aria-label="Your role">
|
||||
@@ -116,6 +123,10 @@ export function DungeonRaceScreen({ onClose }: { readonly onClose: () => void })
|
||||
<button className="front-button" type="button" aria-pressed={boardScope === "dungeon"} onClick={() => setBoardScope("dungeon")}>This dungeon</button></div>
|
||||
{boardScope === "dungeon" && <div className="dungeon-race-screen__choices"><button className="front-button" type="button" aria-pressed={boardView === "wins"} onClick={() => setBoardView("wins")}>Wins & losses</button>
|
||||
<button className="front-button" type="button" aria-pressed={boardView === "times"} onClick={() => setBoardView("times")}>Fastest clears</button></div>}
|
||||
{boardScope === "dungeon" && bossOptions.length > 1 && <label>Boss<select value={selectedBoardBossId}
|
||||
onChange={(event) => setBoardBossId(event.target.value)}>
|
||||
{bossOptions.map((boss) => <option key={boss.id} value={boss.id}>{boss.name}</option>)}
|
||||
</select></label>}
|
||||
<div className="dungeon-race-screen__choices"><button className="front-button" type="button" aria-pressed={period === "30d"} onClick={() => setPeriod("30d")}>Last 30 days</button>
|
||||
<button className="front-button" type="button" aria-pressed={period === "all"} onClick={() => setPeriod("all")}>All time</button></div>
|
||||
{boardError && <p role="status">{boardError}</p>}
|
||||
|
||||
Reference in new issue
Block a user