import React, { useEffect, useState, useCallback } from 'react'; import { Alert, Box, Button, CircularProgress, Container, FormControl, Grid, InputLabel, MenuItem, Paper, Select, TextField, Typography, } from '@mui/material'; import { ArrowBack, Save } from '@mui/icons-material'; import { useNavigate, useParams } from 'react-router-dom'; import DashboardLayout from '../components/dashboard/DashboardLayout'; import { vehiclesApi } from '../services/vehicles'; import { toGermanDate, fromGermanDate } from '../utils/dateInput'; import { FahrzeugStatus, FahrzeugStatusLabel, CreateFahrzeugPayload, UpdateFahrzeugPayload, } from '../types/vehicle.types'; import { usePermissions } from '../hooks/usePermissions'; // ── Form state shape ────────────────────────────────────────────────────────── interface FormState { bezeichnung: string; kurzname: string; amtliches_kennzeichen: string; fahrgestellnummer: string; baujahr: string; // kept as string for input, parsed on submit hersteller: string; typ_schluessel: string; besatzung_soll: string; status: FahrzeugStatus; status_bemerkung: string; standort: string; bild_url: string; paragraph57a_faellig_am: string; // ISO date 'YYYY-MM-DD' or '' naechste_wartung_am: string; // ISO date 'YYYY-MM-DD' or '' } const EMPTY_FORM: FormState = { bezeichnung: '', kurzname: '', amtliches_kennzeichen: '', fahrgestellnummer: '', baujahr: '', hersteller: '', typ_schluessel: '', besatzung_soll: '', status: FahrzeugStatus.Einsatzbereit, status_bemerkung: '', standort: 'Feuerwehrhaus', bild_url: '', paragraph57a_faellig_am: '', naechste_wartung_am: '', }; // ── Helpers ─────────────────────────────────────────────────────────────────── /** Convert a Date ISO string like '2026-03-15T00:00:00.000Z' to 'DD.MM.YYYY' */ function toDateInput(iso: string | null | undefined): string { return toGermanDate(iso); } // ── Component ───────────────────────────────────────────────────────────────── function FahrzeugForm() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { isAdmin } = usePermissions(); const isEditMode = Boolean(id); // ── Permission guard: only admins may create or edit vehicles ────────────── if (!isAdmin) { return ( Keine Berechtigung Sie haben nicht die erforderlichen Rechte, um Fahrzeuge zu bearbeiten. ); } const [form, setForm] = useState(EMPTY_FORM); const [loading, setLoading] = useState(isEditMode); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [saveError, setSaveError] = useState(null); const [fieldErrors, setFieldErrors] = useState>>({}); const fetchVehicle = useCallback(async () => { if (!id) return; try { setLoading(true); setError(null); const vehicle = await vehiclesApi.getById(id); setForm({ bezeichnung: vehicle.bezeichnung, kurzname: vehicle.kurzname ?? '', amtliches_kennzeichen: vehicle.amtliches_kennzeichen ?? '', fahrgestellnummer: vehicle.fahrgestellnummer ?? '', baujahr: vehicle.baujahr?.toString() ?? '', hersteller: vehicle.hersteller ?? '', typ_schluessel: vehicle.typ_schluessel ?? '', besatzung_soll: vehicle.besatzung_soll ?? '', status: vehicle.status, status_bemerkung: vehicle.status_bemerkung ?? '', standort: vehicle.standort, bild_url: vehicle.bild_url ?? '', paragraph57a_faellig_am: toDateInput(vehicle.paragraph57a_faellig_am), naechste_wartung_am: toDateInput(vehicle.naechste_wartung_am), }); } catch { setError('Fahrzeug konnte nicht geladen werden.'); } finally { setLoading(false); } }, [id]); useEffect(() => { if (isEditMode) fetchVehicle(); }, [isEditMode, fetchVehicle]); const validate = (): boolean => { const errors: Partial> = {}; if (!form.bezeichnung.trim()) { errors.bezeichnung = 'Bezeichnung ist erforderlich.'; } setFieldErrors(errors); return Object.keys(errors).length === 0; }; const handleSubmit = async () => { if (!validate()) return; try { setSaving(true); setSaveError(null); if (isEditMode && id) { const payload: UpdateFahrzeugPayload = { bezeichnung: form.bezeichnung.trim() || undefined, kurzname: form.kurzname.trim() || undefined, amtliches_kennzeichen: form.amtliches_kennzeichen.trim() || undefined, fahrgestellnummer: form.fahrgestellnummer.trim() || undefined, baujahr: form.baujahr ? Number(form.baujahr) : undefined, hersteller: form.hersteller.trim() || undefined, typ_schluessel: form.typ_schluessel.trim() || undefined, besatzung_soll: form.besatzung_soll.trim() || undefined, status: form.status, status_bemerkung: form.status_bemerkung.trim() || undefined, standort: form.standort.trim() || 'Feuerwehrhaus', bild_url: form.bild_url.trim() || undefined, paragraph57a_faellig_am: form.paragraph57a_faellig_am ? fromGermanDate(form.paragraph57a_faellig_am) || undefined : undefined, naechste_wartung_am: form.naechste_wartung_am ? fromGermanDate(form.naechste_wartung_am) || undefined : undefined, }; await vehiclesApi.update(id, payload); navigate(`/fahrzeuge/${id}`); } else { const payload: CreateFahrzeugPayload = { bezeichnung: form.bezeichnung.trim(), kurzname: form.kurzname.trim() || undefined, amtliches_kennzeichen: form.amtliches_kennzeichen.trim() || undefined, fahrgestellnummer: form.fahrgestellnummer.trim() || undefined, baujahr: form.baujahr ? Number(form.baujahr) : undefined, hersteller: form.hersteller.trim() || undefined, typ_schluessel: form.typ_schluessel.trim() || undefined, besatzung_soll: form.besatzung_soll.trim() || undefined, status: form.status, status_bemerkung: form.status_bemerkung.trim() || undefined, standort: form.standort.trim() || 'Feuerwehrhaus', bild_url: form.bild_url.trim() || undefined, paragraph57a_faellig_am: form.paragraph57a_faellig_am ? fromGermanDate(form.paragraph57a_faellig_am) || undefined : undefined, naechste_wartung_am: form.naechste_wartung_am ? fromGermanDate(form.naechste_wartung_am) || undefined : undefined, }; const newVehicle = await vehiclesApi.create(payload); navigate(`/fahrzeuge/${newVehicle.id}`); } } catch { setSaveError( isEditMode ? 'Fahrzeug konnte nicht gespeichert werden.' : 'Fahrzeug konnte nicht erstellt werden.' ); } finally { setSaving(false); } }; const f = (field: keyof FormState) => ({ value: form[field] as string, onChange: (e: React.ChangeEvent) => setForm((prev) => ({ ...prev, [field]: e.target.value })), error: Boolean(fieldErrors[field]), helperText: fieldErrors[field], }); if (loading) { return ( ); } if (error) { return ( {error} ); } return ( {isEditMode ? 'Fahrzeug bearbeiten' : 'Neues Fahrzeug erfassen'} {saveError && {saveError}} Stammdaten Status Status Prüf- und Wartungsfristen setForm((prev) => ({ ...prev, paragraph57a_faellig_am: e.target.value }))} InputLabelProps={{ shrink: true }} helperText="Periodische Begutachtung (§57a StVO)" /> setForm((prev) => ({ ...prev, naechste_wartung_am: e.target.value }))} InputLabelProps={{ shrink: true }} helperText="Nächster geplanter Servicetermin" /> Bild ); } export default FahrzeugForm;