// frontend\src\pages\operations\CreateOperationModal.tsx import { useEffect, useState, type FormEvent, type MouseEvent } from 'react' import { DialogTitle } from '@headlessui/react' import { XMarkIcon } from '@heroicons/react/24/outline' import { CheckIcon, ChevronLeftIcon, ChevronRightIcon, } from '@heroicons/react/20/solid' import Modal from '../../components/Modal' import Button from '../../components/Button' import AddressCombobox from '../../components/AddressCombobox' import { formatOperationNumberInput, isCompleteOperationNumber } from '../../components/formatter' type CreateOperationModalProps = { open: boolean setOpen: (open: boolean) => void isSaving: boolean error: string | null onSubmit: (event: FormEvent) => void } type OperationFormValues = { operationNumber: string operationName: string offense: string caseWorker: string targetObject: string kwAddress: string operationLeader: string operationTeam: string legend: string camera: string router: string technology: string switchbox: string hardDrive: string laptop: string remark: string } type SetupStepId = | 'masterData' | 'addresses' | 'responsibilities' | 'notes' | 'equipment' | 'review' const inputClassName = 'block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500' const textareaClassName = 'block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6 dark:bg-white/5 dark:text-white dark:outline-white/10 dark:placeholder:text-gray-500 dark:focus:outline-indigo-500' const initialFormValues: OperationFormValues = { operationNumber: '', operationName: '', offense: '', caseWorker: '', targetObject: '', kwAddress: '', operationLeader: '', operationTeam: '', legend: '', camera: '', router: '', technology: '', switchbox: '', hardDrive: '', laptop: '', remark: '', } const setupSteps: Array<{ id: SetupStepId title: string description: string optional?: boolean }> = [ { id: 'masterData', title: 'Stammdaten', description: 'Einsatznummer, Name und Delikt.', }, { id: 'addresses', title: 'Adressen', description: 'KW-Adresse und Zielobjekt mit Kartenvorschau.', optional: true, }, { id: 'responsibilities', title: 'Zuständigkeiten', description: 'Sachbearbeitung, Einsatzleitung und Einsatzteam.', optional: true, }, { id: 'notes', title: 'Zusatzinfos', description: 'Legende und Bemerkung.', optional: true, }, { id: 'equipment', title: 'Technik', description: 'Kamera, Router, Switchbox und Laptop.', optional: true, }, { id: 'review', title: 'Prüfen', description: 'Daten prüfen und Einsatz speichern.', }, ] function classNames(...classes: Array) { return classes.filter(Boolean).join(' ') } function getStepIndex(stepId: SetupStepId) { return setupSteps.findIndex((step) => step.id === stepId) } function getDisplayValue(value: string) { return value.trim() || '—' } function ReviewItem({ label, value, }: { label: string value: string }) { return (
{label}
{getDisplayValue(value)}
) } function StepHeader({ title, description, }: { title: string description: string }) { return (

{title}

{description}

) } export default function CreateOperationModal({ open, setOpen, isSaving, error, onSubmit, }: CreateOperationModalProps) { const [activeStep, setActiveStep] = useState('masterData') const [formValues, setFormValues] = useState(initialFormValues) const [localError, setLocalError] = useState(null) const activeStepIndex = getStepIndex(activeStep) const isFirstStep = activeStepIndex === 0 const isLastStep = activeStepIndex === setupSteps.length - 1 useEffect(() => { if (!open) { return } setActiveStep('masterData') setFormValues(initialFormValues) setLocalError(null) }, [open]) function handleOpenChange(nextOpen: boolean) { if (!nextOpen && isSaving) { return } setOpen(nextOpen) } function updateField(field: keyof OperationFormValues, value: string) { const nextValue = field === 'operationNumber' ? formatOperationNumberInput(value) : value setFormValues((currentValues) => ({ ...currentValues, [field]: nextValue, })) if (localError) { setLocalError(null) } } function goToStep(stepId: SetupStepId) { setActiveStep(stepId) } function goToPreviousStep() { if (isFirstStep) { return } setActiveStep(setupSteps[activeStepIndex - 1].id) } function goToNextStep(event?: MouseEvent) { event?.preventDefault() event?.stopPropagation() if (isLastStep) { return } if (activeStep === 'masterData') { if (formValues.operationNumber.trim() === '') { setLocalError('Bitte zuerst eine Einsatznummer eintragen.') return } if (!isCompleteOperationNumber(formValues.operationNumber)) { setLocalError('Die Einsatznummer muss das Format 000-00-0000 haben.') return } } setActiveStep(setupSteps[activeStepIndex + 1].id) } function skipStep() { if (isLastStep) { return } setActiveStep(setupSteps[activeStepIndex + 1].id) } function handleSubmit(event: FormEvent) { event.preventDefault() if (activeStep !== 'review') { goToNextStep() return } if (formValues.operationNumber.trim() === '') { setLocalError('Einsatznummer ist erforderlich.') setActiveStep('masterData') return } if (!isCompleteOperationNumber(formValues.operationNumber)) { setLocalError('Die Einsatznummer muss das Format 000-00-0000 haben.') setActiveStep('masterData') return } onSubmit(event) } const combinedError = localError || error return (
Einsatz anlegen

Folge den Schritten oder überspringe optionale Bereiche.

{combinedError && (
{combinedError}
)}
{activeStep === 'masterData' && (
updateField('operationNumber', event.target.value)} className={inputClassName} autoFocus />
updateField('operationName', event.target.value)} className={inputClassName} />
updateField('offense', event.target.value)} className={inputClassName} />
)} {activeStep === 'addresses' && (
updateField('kwAddress', value)} placeholder="KW-Adresse suchen oder eingeben" /> updateField('targetObject', value)} placeholder="Adresse suchen oder Zielobjekt eingeben" />
)} {activeStep === 'responsibilities' && (
updateField('caseWorker', event.target.value)} className={inputClassName} />
updateField('operationLeader', event.target.value)} className={inputClassName} />
updateField('operationTeam', event.target.value)} className={inputClassName} />
)} {activeStep === 'notes' && (