'use client'; import { useEffect, useState } from 'react'; import { ARBEITSZEIT_KUNDE_FIX, type ArbeitszeitEintrag } from '@/types/arbeitszeit'; import { toDecimalHours, mehrarbeit, weekdayName, formatHours, hatZeiten } from '@/lib/calc'; interface Props { pause: number; refreshKey: number; onEdit: (entry: ArbeitszeitEintrag) => void; limit?: number; compact?: boolean; } const pad = (n: number) => String(n).padStart(2, '0'); const MONATE = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember']; function currentMonth() { const d = new Date(); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}`; } function monthLabel(ym: string) { const [y, m] = ym.split('-').map(Number); return `${MONATE[m - 1]} ${y}`; } function prevMonth(ym: string) { const [y, m] = ym.split('-').map(Number); return m === 1 ? `${y - 1}-12` : `${y}-${pad(m - 1)}`; } function nextMonth(ym: string) { const [y, m] = ym.split('-').map(Number); return m === 12 ? `${y + 1}-01` : `${y}-${pad(m + 1)}`; } function formatDate(d: string) { const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(d); return m ? `${m[3]}.${m[2]}.${m[1]}` : d; } export default function ArbeitszeitList({ pause, refreshKey, onEdit, limit = 15, compact = false }: Props) { const [entries, setEntries] = useState([]); const [month, setMonth] = useState(compact ? '' : currentMonth()); const [deleteId, setDeleteId] = useState(null); const [deleteErr, setDeleteErr] = useState(''); // Lade-/Fehlerzustand wird aus dem Ergebnis abgeleitet, nicht synchron im Effekt gesetzt. const paramsKey = `${refreshKey}|${limit}|${month}`; const [fetchResult, setFetchResult] = useState<{ ok: boolean; forKey: string } | null>(null); const loading = fetchResult?.forKey !== paramsKey; const fetchError = fetchResult?.forKey === paramsKey && !fetchResult.ok ? 'Fehler beim Laden.' : ''; const error = fetchError || deleteErr; useEffect(() => { let cancelled = false; const url = `/api/arbeitszeit?limit=${limit}&offset=0` + (month ? `&month=${encodeURIComponent(month)}` : ''); fetch(url) .then((r) => { if (!r.ok) throw new Error(); return r.json(); }) .then((data) => { if (!cancelled) { setEntries(data.entries); setDeleteErr(''); setFetchResult({ ok: true, forKey: paramsKey }); } }) .catch(() => { if (!cancelled) setFetchResult({ ok: false, forKey: paramsKey }); }); return () => { cancelled = true; }; }, [refreshKey, limit, month, paramsKey]); async function confirmDelete(id: number) { try { const res = await fetch(`/api/arbeitszeit/${id}`, { method: 'DELETE' }); if (!res.ok) throw new Error(); setEntries((prev) => prev.filter((e) => e.id !== id)); } catch { setDeleteErr('Fehler beim Löschen.'); } finally { setDeleteId(null); } } const cell = compact ? 'px-1.5 py-1 border border-gray-200 text-xs text-gray-900' : 'px-3 py-2 border border-gray-200 text-gray-900'; const head = compact ? 'px-1.5 py-1 border border-gray-300 text-xs font-semibold text-gray-900' : 'px-3 py-2 border border-gray-300 text-gray-900'; return (
{!compact && (
setMonth(e.target.value > currentMonth() ? currentMonth() : e.target.value)} className="border border-green-600 rounded-lg px-2 py-1 text-sm text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-green-700" /> {month !== currentMonth() && ( )}
)} {loading &&
Lade Einträge...
} {error &&
{error}
} {!loading && !error && (
{entries.length === 0 ? ( ) : entries.map((e) => { const zeiten = hatZeiten(e.beginn, e.ende); const mehr = mehrarbeit(toDecimalHours(e.beginn, e.ende), pause); return ( ); })}
Datum Wochentag Ort Arbeitszeit Kunde Mehrarbeit Reisezeit Vertriebsunt. Kommentar Aktionen
{month ? `Keine Einträge für ${monthLabel(month)}.` : 'Keine Einträge vorhanden.'}
{formatDate(e.datum)} {weekdayName(e.datum)} {e.ort} {zeiten ? formatHours(ARBEITSZEIT_KUNDE_FIX) : '—'} {zeiten ? formatHours(mehr) : '—'} {e.reisezeit ? formatHours(e.reisezeit) : '—'} {e.vertriebsunterstuetzung ? formatHours(e.vertriebsunterstuetzung) : '—'} {e.kommentar}
)} {deleteId !== null && (

Eintrag löschen?

Dieser Eintrag wird unwiderruflich gelöscht.

)}
); }