Files
fotospiel-app/resources/js/guest/polling/usePollStats.ts
Codex Agent 6062b4201b
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled
Update guest v2 home and tasks experience
2026-02-03 18:59:30 +01:00

92 lines
2.4 KiB
TypeScript

import { useEffect, useRef, useState } from 'react';
export type EventStats = {
onlineGuests: number;
tasksSolved: number;
guestCount: number;
likesCount: number;
latestPhotoAt: string | null;
};
type StatsResponse = {
online_guests?: number;
tasks_solved?: number;
guest_count?: number;
likes_count?: number;
latest_photo_at?: string;
};
export function usePollStats(eventKey: string | null | undefined) {
const [data, setData] = useState<EventStats>({
onlineGuests: 0,
tasksSolved: 0,
guestCount: 0,
likesCount: 0,
latestPhotoAt: null,
});
const [loading, setLoading] = useState(true);
const timer = useRef<number | null>(null);
const [visible, setVisible] = useState(
typeof document !== 'undefined' ? document.visibilityState === 'visible' : true
);
const canPoll = Boolean(eventKey);
async function fetchOnce(activeKey: string) {
try {
const res = await fetch(`/api/v1/events/${encodeURIComponent(activeKey)}/stats`, {
headers: { 'Cache-Control': 'no-store' },
});
if (res.status === 304) return;
if (!res.ok) {
if (res.status === 404) {
setData({
onlineGuests: 0,
tasksSolved: 0,
guestCount: 0,
likesCount: 0,
latestPhotoAt: null,
});
}
return;
}
const json: StatsResponse = await res.json();
setData({
onlineGuests: json.online_guests ?? 0,
tasksSolved: json.tasks_solved ?? 0,
guestCount: json.guest_count ?? 0,
likesCount: json.likes_count ?? 0,
latestPhotoAt: json.latest_photo_at ?? null,
});
} finally {
setLoading(false);
}
}
useEffect(() => {
const onVis = () => setVisible(document.visibilityState === 'visible');
document.addEventListener('visibilitychange', onVis);
return () => document.removeEventListener('visibilitychange', onVis);
}, []);
useEffect(() => {
if (!canPoll) {
setLoading(false);
return;
}
setLoading(true);
const activeKey = String(eventKey);
fetchOnce(activeKey);
if (timer.current) window.clearInterval(timer.current);
if (visible) {
timer.current = window.setInterval(() => fetchOnce(activeKey), 10_000);
}
return () => {
if (timer.current) window.clearInterval(timer.current);
};
}, [eventKey, visible, canPoll]);
return { ...data, loading };
}