'use client'; import { useEffect, useMemo, useState } from 'react'; import type { Kuppel } from '@/types/logbuch'; import { artLabel } from '@/types/logbuch'; interface MonthlyRow { monat: number; ArtFuehrung: string; besucher: number; anzahl: number; } interface StatsData { monthly: MonthlyRow[]; cumulative: number; tage: number; allCumulative: number; allTage: number; year: number; kuppel: Kuppel; } const MONATE = [ 'Januar','Februar','März','April','Mai','Juni', 'Juli','August','September','Oktober','November','Dezember', ]; interface Props { kuppel: Kuppel; } export default function Statistik({ kuppel }: Props) { const [year, setYear] = useState(new Date().getFullYear()); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); useEffect(() => { setLoading(true); setError(''); fetch(`/api/statistik?kuppel=${encodeURIComponent(kuppel)}&year=${year}`) .then((r) => { if (!r.ok) throw new Error(); return r.json(); }) .then((d: StatsData) => { setData(d); setLoading(false); }) .catch(() => { setError('Fehler beim Laden der Statistik.'); setLoading(false); }); }, [kuppel, year]); const { arten, matrix, monatTotal, artTotal, grandTotal, anzahlTotal } = useMemo(() => { if (!data) { return { arten: [] as string[], matrix: [] as (number | null)[][], monatTotal: [] as number[], artTotal: [] as number[], grandTotal: 0, anzahlTotal: [] as number[] }; } const artenSet = new Set(); data.monthly.forEach((r) => artenSet.add(r.ArtFuehrung)); const arten = Array.from(artenSet).sort(); const matrix: (number | null)[][] = []; const monatTotal: number[] = []; const anzahlTotal: number[] = []; const artTotal: number[] = new Array(arten.length).fill(0); let grandTotal = 0; for (let m = 1; m <= 12; m++) { const row: (number | null)[] = []; let mSum = 0; let aSum = 0; arten.forEach((art, idx) => { const found = data.monthly.find((r) => r.monat === m && r.ArtFuehrung === art); const val = found ? found.besucher : null; row.push(val); if (val !== null) { mSum += val; artTotal[idx] += val; aSum += found!.anzahl; } }); matrix.push(row); monatTotal.push(mSum); anzahlTotal.push(aSum); grandTotal += mSum; } return { arten, matrix, monatTotal, artTotal, grandTotal, anzahlTotal }; }, [data]); if (loading) return
Lade Statistik...
; if (error) return
{error}
; const headCls = 'px-3 py-2 border border-gray-300 text-xs font-semibold bg-gray-100 whitespace-nowrap'; const cellCls = 'px-3 py-2 border border-gray-200 text-sm text-right tabular-nums'; const labelCls = 'px-3 py-2 border border-gray-200 text-sm text-left whitespace-nowrap'; return (
setYear(parseInt(e.target.value, 10) || new Date().getFullYear())} min={2000} max={2100} className="w-24 px-2 py-1 border-2 border-gray-400 rounded-lg bg-white text-sm focus:border-blue-500 focus:outline-none" />
{arten.map((art) => ( ))} {MONATE.map((name, idx) => { const mSum = monatTotal[idx]; const aSum = anzahlTotal[idx]; return ( 0 ? '' : 'text-gray-400'}> {arten.map((_, aIdx) => { const val = matrix[idx][aIdx]; return ( ); })} ); })} {artTotal.map((t, i) => ( ))}
Monat Führungen{artLabel(art as any) || art}Gesamt
{name} {aSum > 0 ? aSum : ''} {val !== null && val > 0 ? val.toLocaleString('de-DE') : ''} {mSum > 0 ? mSum.toLocaleString('de-DE') : ''}
Summe {anzahlTotal.reduce((s, v) => s + v, 0) > 0 ? anzahlTotal.reduce((s, v) => s + v, 0).toLocaleString('de-DE') : ''}{t > 0 ? t.toLocaleString('de-DE') : ''}{grandTotal > 0 ? grandTotal.toLocaleString('de-DE') : ''}
Kumulierte Besucher {year} ({data?.kuppel})
{data?.cumulative.toLocaleString('de-DE') ?? 0}
Führungstage {year} ({data?.kuppel})
{data?.tage ?? 0}
Kumulierte Besucher {year} (Sternwarte gesamt)
{data?.allCumulative.toLocaleString('de-DE') ?? 0}
Führungstage {year} (Sternwarte gesamt)
{data?.allTage ?? 0}
); }