// Öffentliche Statusseite im Statuspage-Stil: Gesamtlage oben, darunter die // freigegebenen Dienste und die Game-Server, unten die Störungs-Historie. // // Adressen stehen hier bewusst nicht — der Server liefert nur Namen. Was auf // dieser Seite auftaucht, entscheidet der Schalter „öffentlich" je Dienst. import { useEffect, useState } from 'react'; import { apiGet } from '../api.js'; import { SkeletonCards } from '../components/Skeleton.jsx'; import UptimeTrack from '../components/UptimeTrack.jsx'; import { useT, useFmt } from '../i18n.jsx'; import { IconCheck, IconWarning, IconClock } from '../icons.jsx'; /** Gesamtlage aus allen Teilen — die schlechteste zählt */ function gesamtlage(daten) { const alles = [ ...(daten.dienste ?? []).map((d) => d.online), ...(daten.server ?? []).map((s) => s.online), ]; if (alles.length === 0) return 'leer'; if (alles.some((o) => o === false)) return alles.every((o) => o === false) ? 'aus' : 'teil'; // null heißt „noch nicht geprüft" und ist keine Störung return alles.some((o) => o === true) ? 'gut' : 'wartet'; } export default function Status() { const { t } = useT(); const { datum } = useFmt(); const [daten, setDaten] = useState(null); const [fehler, setFehler] = useState(false); useEffect(() => { const laden = () => apiGet('/api/status').then(setDaten).catch(() => setFehler(true)); laden(); const timer = setInterval(laden, 60_000); window.scrollTo(0, 0); return () => clearInterval(timer); }, []); const lage = daten ? gesamtlage(daten) : null; const BANNER = { gut: { icon: IconCheck, text: t('status.allOk') }, teil: { icon: IconWarning, text: t('status.partial') }, aus: { icon: IconWarning, text: t('status.majorOutage') }, wartet: { icon: IconClock, text: t('status.waiting') }, leer: { icon: IconClock, text: t('status.nothing') }, }; const Banner = lage ? BANNER[lage].icon : null; return ( <> STATUS {t('status.tag')} {t('nav.status')} {t('status.subtitle')} {fehler && {t('status.error')}} {!fehler && !daten && } {lage && ( {BANNER[lage].text} )} {daten?.dienste?.length > 0 && ( {t('status.services')} {daten.dienste.map((d) => ( {d.name} {d.online === null ? t('status.waiting') : d.online ? t('status.ok') : t('status.down')} ))} )} {daten?.server?.length > 0 && ( {t('status.gameservers')} {daten.server.map((s) => ( {s.icon} {s.name} {s.online ? `${s.players ?? 0}${s.max ? ` / ${s.max}` : ''}` : s.online === null ? t('status.waiting') : t('status.down')} ))} )} {daten && ( {t('status.incidents')} {daten.stoerungen.length === 0 ? ( {t('status.noIncidents')} ) : ( {daten.stoerungen.map((v) => ( {v.name} {datum(`${v.begonnen.replace(' ', 'T')}Z`, { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit', })} {v.beendet ? t('status.minutes', v.minuten) : t('status.ongoing')} ))} )} )} > ); }
{t('status.subtitle')}
{t('status.error')}
{t('status.noIncidents')}