import React, { useEffect, useState, useCallback } from 'react'; import { Alert, Box, Button, CircularProgress, Container, FormControl, FormControlLabel, Grid, InputLabel, MenuItem, Paper, Select, Switch, 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 { equipmentApi } from '../services/equipment'; import { vehiclesApi } from '../services/vehicles'; import { AusruestungStatus, AusruestungStatusLabel, CreateAusruestungPayload, UpdateAusruestungPayload, AusruestungKategorie, } from '../types/equipment.types'; import type { FahrzeugListItem } from '../types/vehicle.types'; import { usePermissions } from '../hooks/usePermissions'; // -- Form state shape --------------------------------------------------------- interface FormState { bezeichnung: string; kategorie_id: string; seriennummer: string; inventarnummer: string; hersteller: string; baujahr: string; // stored as string for input, converted to number on submit status: AusruestungStatus; status_bemerkung: string; ist_wichtig: boolean; fahrzeug_id: string; standort: string; pruef_intervall_monate: string; letzte_pruefung_am: string; naechste_pruefung_am: string; bemerkung: string; } const EMPTY_FORM: FormState = { bezeichnung: '', kategorie_id: '', seriennummer: '', inventarnummer: '', hersteller: '', baujahr: '', status: AusruestungStatus.Einsatzbereit, status_bemerkung: '', ist_wichtig: false, fahrzeug_id: '', standort: 'Lager', pruef_intervall_monate: '', letzte_pruefung_am: '', naechste_pruefung_am: '', bemerkung: '', }; // -- Helpers ------------------------------------------------------------------ /** Convert a Date ISO string like '2026-03-15T00:00:00.000Z' to 'YYYY-MM-DD' */ function toDateInput(iso: string | null | undefined): string { if (!iso) return ''; return iso.slice(0, 10); } // -- Component ---------------------------------------------------------------- function AusruestungForm() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { canChangeStatus } = usePermissions(); const isEditMode = Boolean(id); // -- Permission guard: only authorized users may create or edit equipment ---- if (!canChangeStatus) { return ( Keine Berechtigung Sie haben nicht die erforderlichen Rechte, um Ausrüstung 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>>({}); // -- Lookup data ------------------------------------------------------------ const [categories, setCategories] = useState([]); const [vehicles, setVehicles] = useState([]); const fetchLookups = useCallback(async () => { try { const [cats, vehs] = await Promise.all([ equipmentApi.getCategories(), vehiclesApi.getAll(), ]); setCategories(cats); setVehicles(vehs); } catch { // Non-critical: dropdowns will be empty but form still usable } }, []); const fetchEquipment = useCallback(async () => { if (!id) return; try { setLoading(true); setError(null); const equipment = await equipmentApi.getById(id); setForm({ bezeichnung: equipment.bezeichnung, kategorie_id: equipment.kategorie_id, seriennummer: equipment.seriennummer ?? '', inventarnummer: equipment.inventarnummer ?? '', hersteller: equipment.hersteller ?? '', baujahr: equipment.baujahr?.toString() ?? '', status: equipment.status, status_bemerkung: equipment.status_bemerkung ?? '', ist_wichtig: equipment.ist_wichtig, fahrzeug_id: equipment.fahrzeug_id ?? '', standort: equipment.standort ?? 'Lager', pruef_intervall_monate: equipment.pruef_intervall_monate?.toString() ?? '', letzte_pruefung_am: toDateInput(equipment.letzte_pruefung_am), naechste_pruefung_am: toDateInput(equipment.naechste_pruefung_am), bemerkung: equipment.bemerkung ?? '', }); } catch { setError('Ausrüstung konnte nicht geladen werden.'); } finally { setLoading(false); } }, [id]); useEffect(() => { fetchLookups(); }, [fetchLookups]); useEffect(() => { if (isEditMode) fetchEquipment(); }, [isEditMode, fetchEquipment]); // -- Validation ------------------------------------------------------------- const validate = (): boolean => { const errors: Partial> = {}; if (!form.bezeichnung.trim()) { errors.bezeichnung = 'Bezeichnung ist erforderlich.'; } if (!form.kategorie_id) { errors.kategorie_id = 'Kategorie ist erforderlich.'; } if (form.baujahr) { const year = parseInt(form.baujahr, 10); if (isNaN(year) || year < 1950 || year > 2100) { errors.baujahr = 'Baujahr muss zwischen 1950 und 2100 liegen.'; } } if (form.pruef_intervall_monate) { const months = parseInt(form.pruef_intervall_monate, 10); if (isNaN(months) || months < 1 || months > 120) { errors.pruef_intervall_monate = 'Prüfintervall muss zwischen 1 und 120 Monaten liegen.'; } } setFieldErrors(errors); return Object.keys(errors).length === 0; }; // -- Submit ----------------------------------------------------------------- const handleSubmit = async () => { if (!validate()) return; try { setSaving(true); setSaveError(null); if (isEditMode && id) { const payload: UpdateAusruestungPayload = { bezeichnung: form.bezeichnung.trim() || undefined, kategorie_id: form.kategorie_id || undefined, seriennummer: form.seriennummer.trim() || undefined, inventarnummer: form.inventarnummer.trim() || undefined, hersteller: form.hersteller.trim() || undefined, baujahr: form.baujahr ? parseInt(form.baujahr, 10) : undefined, status: form.status, status_bemerkung: form.status_bemerkung.trim() || undefined, ist_wichtig: form.ist_wichtig, fahrzeug_id: form.fahrzeug_id || null, standort: !form.fahrzeug_id ? (form.standort.trim() || 'Lager') : undefined, pruef_intervall_monate: form.pruef_intervall_monate ? parseInt(form.pruef_intervall_monate, 10) : undefined, letzte_pruefung_am: form.letzte_pruefung_am || undefined, naechste_pruefung_am: form.naechste_pruefung_am || undefined, bemerkung: form.bemerkung.trim() || undefined, }; await equipmentApi.update(id, payload); navigate(`/ausruestung/${id}`); } else { const payload: CreateAusruestungPayload = { bezeichnung: form.bezeichnung.trim(), kategorie_id: form.kategorie_id, seriennummer: form.seriennummer.trim() || undefined, inventarnummer: form.inventarnummer.trim() || undefined, hersteller: form.hersteller.trim() || undefined, baujahr: form.baujahr ? parseInt(form.baujahr, 10) : undefined, status: form.status, status_bemerkung: form.status_bemerkung.trim() || undefined, ist_wichtig: form.ist_wichtig, fahrzeug_id: form.fahrzeug_id || undefined, standort: !form.fahrzeug_id ? (form.standort.trim() || 'Lager') : undefined, pruef_intervall_monate: form.pruef_intervall_monate ? parseInt(form.pruef_intervall_monate, 10) : undefined, letzte_pruefung_am: form.letzte_pruefung_am || undefined, naechste_pruefung_am: form.naechste_pruefung_am || undefined, bemerkung: form.bemerkung.trim() || undefined, }; const created = await equipmentApi.create(payload); navigate(`/ausruestung/${created.id}`); } } catch { setSaveError( isEditMode ? 'Ausrüstung konnte nicht gespeichert werden.' : 'Ausrüstung konnte nicht erstellt werden.' ); } finally { setSaving(false); } }; // -- Field helper ----------------------------------------------------------- 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], }); // -- Loading / Error early returns ------------------------------------------ if (loading) { return ( ); } if (error) { return ( {error} ); } // -- Render ----------------------------------------------------------------- return ( {isEditMode ? 'Gerät bearbeiten' : 'Neues Gerät anlegen'} {saveError && {saveError}} {/* ── Section: Grunddaten ──────────────────────────────────────────── */} Grunddaten Kategorie * {fieldErrors.kategorie_id && ( {fieldErrors.kategorie_id} )} {/* ── Section: Status & Zuordnung ──────────────────────────────────── */} Status & Zuordnung Status {form.status !== AusruestungStatus.Einsatzbereit && ( )} setForm((prev) => ({ ...prev, ist_wichtig: e.target.checked }))} /> } label="Wichtiges Gerät (Warnung auf Fahrzeugkarte wenn nicht einsatzbereit)" /> Fahrzeug {!form.fahrzeug_id && ( )} {/* ── Section: Pruefung & Wartung ───────────────────────────────────── */} Prüfung & Wartung setForm((prev) => ({ ...prev, letzte_pruefung_am: e.target.value }))} InputLabelProps={{ shrink: true }} /> setForm((prev) => ({ ...prev, naechste_pruefung_am: e.target.value }))} InputLabelProps={{ shrink: true }} /> {/* ── Section: Bemerkungen ──────────────────────────────────────────── */} Bemerkungen ); } export default AusruestungForm;