68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
import { useEffect, useRef, useState } from 'react';
|
|
|
|
export type EventStats = {
|
|
onlineGuests: number;
|
|
tasksSolved: number;
|
|
latestPhotoAt: string | null;
|
|
};
|
|
|
|
type StatsResponse = {
|
|
online_guests?: number;
|
|
tasks_solved?: number;
|
|
latest_photo_at?: string;
|
|
};
|
|
|
|
export function usePollStats(eventKey: string | null | undefined) {
|
|
const [data, setData] = useState<EventStats>({ onlineGuests: 0, tasksSolved: 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;
|
|
const json: StatsResponse = await res.json();
|
|
setData({
|
|
onlineGuests: json.online_guests ?? 0,
|
|
tasksSolved: json.tasks_solved ?? 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 };
|
|
}
|