'use client'; import { useState } from 'react'; import { ORTE, ARBEITSZEIT_KUNDE_FIX, type ArbeitszeitEintrag } from '@/types/arbeitszeit'; import { toDecimalHours, mehrarbeit, weekdayName, formatHours, hatZeiten } from '@/lib/calc'; import CustomSelect from './CustomSelect'; import TimeInput from './TimeInput'; interface Props { editEntry?: ArbeitszeitEintrag | null; pause: number; onSaved: () => void; onCancel: () => void; } function todayDate(): string { const now = new Date(); const pad = (n: number) => String(n).padStart(2, '0'); return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`; } // Komma als Dezimaltrenner erlauben function toNum(raw: string): number { const n = parseFloat(raw.replace(',', '.')); return isNaN(n) ? 0 : n; } export default function ArbeitszeitForm({ editEntry, pause, onSaved, onCancel }: Props) { // Diese Komponente wird beim Wechsel von editEntry über `key` neu gemountet, // daher genügt eine einmalige Initialisierung aus editEntry (kein Sync-Effekt nötig). const [datum, setDatum] = useState(editEntry?.datum ?? todayDate()); const [ort, setOrt] = useState(editEntry?.ort ?? ORTE[0]); const [beginn, setBeginn] = useState(editEntry?.beginn ?? ''); const [ende, setEnde] = useState(editEntry?.ende ?? ''); const [reisezeit, setReisezeit] = useState(editEntry ? String(editEntry.reisezeit) : '0'); const [vertrieb, setVertrieb] = useState(editEntry ? String(editEntry.vertriebsunterstuetzung) : '2'); const [kommentar, setKommentar] = useState(editEntry?.kommentar ?? ''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const [success, setSuccess] = useState(false); const zeiten = hatZeiten(beginn, ende); const arbeitszeit = toDecimalHours(beginn, ende); const mehr = mehrarbeit(arbeitszeit, pause); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setError(''); setSuccess(false); const beginnLeer = beginn === ''; const endeLeer = ende === ''; if (beginnLeer !== endeLeer) { setError('Bitte Start- und Endzeit gemeinsam angeben oder beide leer lassen.'); return; } if (!beginnLeer && !endeLeer && arbeitszeit <= 0) { setError('Endzeit muss nach der Startzeit liegen.'); return; } setSaving(true); const body = { datum, ort, beginn, ende, reisezeit: toNum(reisezeit), vertriebsunterstuetzung: toNum(vertrieb), kommentar, }; const url = editEntry ? `/api/arbeitszeit/${editEntry.id}` : '/api/arbeitszeit'; const method = editEntry ? 'PUT' : 'POST'; try { const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.error || 'Fehler beim Speichern.'); } setSuccess(true); setTimeout(() => setSuccess(false), 4000); onSaved(); } catch (err) { setError(err instanceof Error ? err.message : 'Fehler beim Speichern.'); } finally { setSaving(false); } } const labelCls = 'block text-xs font-medium text-gray-700 mb-0.5'; const numCls = 'w-24 px-2 py-1 border-2 border-gray-400 rounded-lg bg-white text-gray-900 text-sm focus:border-green-600 focus:outline-none'; const wt = weekdayName(datum); return (
{/* Datum + Wochentag / Ort */}
e.target.value && setDatum(e.target.value)} required className="px-2 py-1 border-2 border-gray-400 rounded-lg bg-white text-sm text-gray-900 focus:border-green-600 focus:outline-none" /> {wt}
({ value: o, label: o }))} onChange={setOrt} />
{/* Beginn / Ende / Reisezeit / Vertrieb */}
setReisezeit(e.target.value)} className={numCls} />
setVertrieb(e.target.value)} className={numCls} />
{/* Kommentar */}