64 lines
1.6 KiB
TypeScript
64 lines
1.6 KiB
TypeScript
import React from 'react';
|
|
import { fetchEventStats } from '../services/statsApi';
|
|
import type { EventStats } from '../services/eventApi';
|
|
|
|
const defaultStats: EventStats = {
|
|
onlineGuests: 0,
|
|
tasksSolved: 0,
|
|
guestCount: 0,
|
|
likesCount: 0,
|
|
latestPhotoAt: null,
|
|
};
|
|
|
|
export function usePollStats(eventToken: string | null, intervalMs = 10000) {
|
|
const [stats, setStats] = React.useState<EventStats>(defaultStats);
|
|
const [loading, setLoading] = React.useState<boolean>(Boolean(eventToken));
|
|
const [error, setError] = React.useState<string | null>(null);
|
|
|
|
React.useEffect(() => {
|
|
if (!eventToken) {
|
|
setStats(defaultStats);
|
|
setLoading(false);
|
|
setError(null);
|
|
return;
|
|
}
|
|
|
|
let active = true;
|
|
let timer: number | null = null;
|
|
|
|
const poll = async () => {
|
|
if (document.visibilityState === 'hidden') {
|
|
timer = window.setTimeout(poll, intervalMs);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setLoading(true);
|
|
const next = await fetchEventStats(eventToken);
|
|
if (!active) return;
|
|
setStats(next);
|
|
setError(null);
|
|
} catch (err) {
|
|
if (!active) return;
|
|
setError(err instanceof Error ? err.message : 'Failed to load stats');
|
|
} finally {
|
|
if (active) {
|
|
setLoading(false);
|
|
timer = window.setTimeout(poll, intervalMs);
|
|
}
|
|
}
|
|
};
|
|
|
|
poll();
|
|
|
|
return () => {
|
|
active = false;
|
|
if (timer) {
|
|
window.clearTimeout(timer);
|
|
}
|
|
};
|
|
}, [eventToken, intervalMs]);
|
|
|
|
return { stats, loading, error } as const;
|
|
}
|