Files
healer-man/src/ui/useDungeonLeaderboard.ts
T
2026-09-27 21:48:00 -04:00

34 lines
2.2 KiB
TypeScript

import { useEffect, useState } from "react";
import { fetchDungeonLeaderboard, localDungeonLeaderboard, subscribeDungeonLeaderboard,
type LeaderboardScope } from "../app/dungeonLeaderboardClient";
import type { DungeonClearFilter, DungeonLeaderboard } from "../game/dungeonRunTypes";
export function useDungeonLeaderboard(dungeonId: string, difficultyId: string, filter: DungeonClearFilter,
bossDifficulty = 1, bossId?: string, spotId?: string, spotRevision?: number) {
const [offset, setOffset] = useState(0);
const [revision, setRevision] = useState(0);
const [state, setState] = useState<{ data: DungeonLeaderboard; scope: LeaderboardScope; loading: boolean }>({
data: { entries: [], total: 0 }, scope: "world", loading: true,
});
useEffect(() => { setOffset(0); }, [dungeonId, difficultyId, filter, bossDifficulty, bossId, spotId, spotRevision]);
useEffect(() => subscribeDungeonLeaderboard(() => setRevision((value) => value + 1)), []);
useEffect(() => {
const refresh = () => setRevision((value) => value + 1);
window.addEventListener("focus", refresh);
return () => window.removeEventListener("focus", refresh);
}, []);
useEffect(() => {
const controller = new AbortController();
let live = true;
const timeout = setTimeout(() => controller.abort(), 8000);
setState({ data: { entries: [], total: 0 }, scope: "world", loading: true });
if (dungeonId) void fetchDungeonLeaderboard(dungeonId, difficultyId, filter, offset, controller.signal, bossDifficulty, bossId, spotId, spotRevision)
.then((data) => { if (live) setState({ data, scope: "world", loading: false }); })
.catch(() => { if (live) setState({ data: localDungeonLeaderboard(dungeonId, difficultyId, filter, offset, bossDifficulty, bossId, spotId, spotRevision),
scope: "device", loading: false }); });
else setState({ data: { entries: [], total: 0 }, scope: "world", loading: false });
return () => { live = false; controller.abort(); clearTimeout(timeout); };
}, [dungeonId, difficultyId, filter, offset, revision, bossDifficulty, bossId, spotId, spotRevision]);
return { ...state, offset, setOffset, refresh: () => setRevision((value) => value + 1) };
}