// Ö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
{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')}
))}
)}
)}
); }