// Home / Dashboard - "Startseite mit großen Aktionen" function Home({ onNav, accent, density }) { const [stats, setStats] = React.useState(null); const [schuljahresBeginn, setSchuljahresBeginn] = React.useState(null); const [unversandt, setUnversandt] = React.useState([]); React.useEffect(() => { window.api.dashboard().then(setStats).catch(console.error); window.api.einstellungen.get().then(e => { if (e.schuljahr_naechster_beginn) setSchuljahresBeginn(e.schuljahr_naechster_beginn); }).catch(console.error); window.api.buchhaltung.unversandt().then(res => setUnversandt(res.items || [])).catch(console.error); }, []); const ActionCard = ({ id, icon, title, subtitle, tone }) => ( ); const Stat = ({ label, value, hint, hintTone }) => (
{label}
{value}
{hint &&
{hint}
}
); if (!stats) { return
Lade Dashboard...
; } const heute = new Date(); heute.setHours(0, 0, 0, 0); const terminDatum = schuljahresBeginn ? new Date(schuljahresBeginn) : null; const tageVerbleibend = terminDatum ? Math.ceil((terminDatum - heute) / 86400000) : null; const terminIstHeute = tageVerbleibend === 0; const terminAbgelaufen = tageVerbleibend !== null && tageVerbleibend < 0; const hour = new Date().getHours(); let greeting = "Guten Morgen"; if (hour >= 12 && hour < 18) greeting = "Guten Tag"; else if (hour >= 18) greeting = "Guten Abend"; return (
{new Date().toLocaleDateString('de-DE', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}

{greeting}.

Was möchten Sie als Nächstes erledigen?
{/* Big action cards */}
{/* Stats strip */}
{/* Recent activity & Infos */}
Letzte Vorgänge
{stats.letzte_vorgaenge.length === 0 ? (
Noch keine Vorgänge vorhanden.
) : stats.letzte_vorgaenge.map((v, i) => { const typMeta = { rechnung: { tone: 'blue', icon: 'invoice', label: 'Rechnung' }, gutschrift: { tone: 'green', icon: 'return', label: 'Gutschrift' }, zahlung: { tone: 'slate', icon: 'check', label: 'Zahlung' }, auszahlung: { tone: 'orange', icon: 'arrow-right', label: 'Auszahlung' }, }[v.typ] || { tone: 'slate', icon: 'circle', label: v.typ }; const betrag = v.betrag_cents / 100; const betragFarbe = betrag >= 0 ? '#047857' : '#0f172a'; const erstellt = new Date(v.erstellt_am.replace(' ', 'T') + 'Z'); const jetzt = new Date(); const diffMin = Math.floor((jetzt - erstellt) / 60000); let zeitLabel; if (diffMin < 1) zeitLabel = 'Gerade eben'; else if (diffMin < 60) zeitLabel = `Vor ${diffMin} Min.`; else if (diffMin < 1440) zeitLabel = `Vor ${Math.floor(diffMin / 60)} Std.`; else zeitLabel = erstellt.toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: '2-digit', hour: '2-digit', minute: '2-digit' }); return (
{typMeta.label}
{v.schueler_name}
{v.typ !== 'zahlung' && v.typ !== 'auszahlung' && ( <> {v.id} · )} {zeitLabel}
{betrag >= 0 ? '+' : ''}{betrag.toFixed(2).replace('.', ',')} €
); })}
0 ? '#b45309' : '#94a3b8' }}>
Unversandte Rechnungen
{unversandt.length === 0 ? (
Alle Rechnungen wurden bereits versandt.
) : ( <>
{unversandt.length}
{unversandt.length === 1 ? 'Rechnung wartet' : 'Rechnungen warten'} auf den Versand per E-Mail.
{unversandt.slice(0, 3).map(r => (
{r.id} {r.schueler_name} {(r.zu_zahlen_cents / 100).toFixed(2).replace('.', ',')} €
))} {unversandt.length > 3 && (
… und {unversandt.length - 3} weitere
)}
)}
Schuljahresbeginn
{tageVerbleibend === null ? (
Kein Termin konfiguriert.{' '} In den Einstellungen unter „Nächster Schuljahresbeginn" eintragen.
) : terminIstHeute ? (
Heute ist der erste Tag des neuen Schuljahres!
Jetzt Klassenversetzung durchführen.
) : terminAbgelaufen ? (
Schuljahresbeginn war vor{' '} {Math.abs(tageVerbleibend)} {Math.abs(tageVerbleibend) === 1 ? 'Tag' : 'Tagen'}.
Versetzung steht noch aus.
) : (
Noch{' '} {tageVerbleibend} {tageVerbleibend === 1 ? 'Tag' : 'Tage'} {' '} bis zum{' '} {terminDatum.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' })}.
)}
); } window.Home = Home;