import { useCallback, useEffect, useState } from 'react'; import { ApiError, api } from './api'; import type { ScrapeState, ScrapeSummary } from './types'; /** Was am Ende eines Laufs in der Meldung steht. */ export function scrapeBericht(result: ScrapeSummary): string { const parts = [`${result.scannedPlayers} Profile geprüft`]; if (result.newRows > 0) parts.push(`${result.newRows} neue Pakete gefunden`); if (result.awaitingConfirmation > 0) parts.push(`${result.awaitingConfirmation} warten schon`); if (result.unclear > 0) parts.push(`${result.unclear} ungeklärt`); if (result.duplicates > 0) parts.push(`${result.duplicates} schon gebucht`); if (result.failedPlayers.length > 0) { parts.push(`${result.failedPlayers.length} nicht erreichbar`); } const offen = result.newRows + result.awaitingConfirmation; return ( parts.join(', ') + (offen > 0 ? '. Beim Spieler oder unter Import buchen, damit die Guthaben entstehen.' : '.') ); } /** * Stößt einen GExtension-Abgleich an und verfolgt ihn. * * Der Lauf geht über dutzende Profile, zwischen denen gewartet wird - er * läuft deshalb im Hintergrund weiter, auch wenn die Seite gewechselt wird. * Hier wird nur nachgefragt, wie weit er ist. */ export function useScrape(options: { onDone: (bericht: string) => void; onError: (message: string) => void; onFinished?: () => void | Promise; }) { const { onDone, onError, onFinished } = options; const [state, setState] = useState(null); const [running, setRunning] = useState(false); // Ein Lauf aus einer anderen Sitzung - oder vom Zeitplan - soll hier // ebenfalls sichtbar sein. useEffect(() => { void (async () => { try { const aktuell = await api('/api/scrape/status'); setState(aktuell); if (aktuell.running) setRunning(true); } catch { // Ohne Stand bleibt der Knopf einfach bedienbar. } })(); }, []); useEffect(() => { if (!running) return; const abfragen = async () => { try { const aktuell = await api('/api/scrape/status'); setState(aktuell); if (aktuell.running) return; setRunning(false); if (aktuell.error) onError(aktuell.error); else if (aktuell.summary) onDone(scrapeBericht(aktuell.summary)); await onFinished?.(); } catch (err) { setRunning(false); onError(err instanceof ApiError ? err.message : 'Abgleich fehlgeschlagen'); } }; const timer = window.setInterval(() => void abfragen(), 1500); return () => window.clearInterval(timer); }, [running, onDone, onError, onFinished]); const start = useCallback( async (pfad: string) => { try { setState(await api(pfad, { method: 'POST', body: {} })); setRunning(true); } catch (err) { onError(err instanceof ApiError ? err.message : 'Abgleich fehlgeschlagen'); } }, [onError], ); return { state, running, start }; }