import { useEffect, useMemo, useState } from "react"; import { Loader2, Calendar } from "lucide-react"; import { Button, Group, Modal, NumberInput, Select, MultiSelect, SimpleGrid, Stack, Text, Textarea, TextInput, ActionIcon, } from "@mantine/core"; import { FLEET_SELECT_NONE, type FleetFormFieldDef, } from "@/pages/fleet/config/resources"; import type { FleetRecord } from "@/services/fleet/fleet.service"; export interface FleetFormDialogProps { open: boolean; onOpenChange: (open: boolean) => void; title: string; fields: FleetFormFieldDef[]; initialRecord?: FleetRecord | null; emptyValues: Record; isSubmitting: boolean; selectOptionsLoading?: boolean; onSubmit: (values: Record) => void; } const buildInitialValues = ( fields: FleetFormFieldDef[], emptyValues: Record, record?: FleetRecord | null, ): Record => { const values: Record = { ...emptyValues }; if (!record) return values; fields.forEach((field) => { const raw = (record as unknown as Record)[field.name]; if (raw === null || raw === undefined) { values[field.name] = field.noneOption ? FLEET_SELECT_NONE : ""; return; } values[field.name] = raw; }); return values; }; const FleetFormDialog = ({ open, onOpenChange, title, fields, initialRecord, emptyValues, isSubmitting, selectOptionsLoading, onSubmit, }: FleetFormDialogProps) => { const [values, setValues] = useState>({}); const [errors, setErrors] = useState>({}); useEffect(() => { if (open) { setValues(buildInitialValues(fields, emptyValues, initialRecord)); setErrors({}); } }, [open, fields, emptyValues, initialRecord]); const shortFields = useMemo( () => fields.filter((f) => f.type !== "textarea"), [fields], ); const longFields = useMemo( () => fields.filter((f) => f.type === "textarea"), [fields], ); const validate = () => { const next: Record = {}; fields.forEach((field) => { const value = values[field.name]; const stringValue = typeof value === "string" ? value.trim() : String(value ?? ""); if ( field.required && (stringValue === "" || stringValue === FLEET_SELECT_NONE) ) { next[field.name] = `${field.label} is required`; } // Validate date format (YYYY-MM-DD) - DatePicker ensures this if ( field.type === "date" && stringValue && stringValue !== FLEET_SELECT_NONE ) { const dateRegex = /^\d{4}-\d{2}-\d{2}$/; if (!dateRegex.test(stringValue)) { next[field.name] = `${field.label} must be a valid date`; } else { const date = new Date(stringValue + "T00:00:00Z"); if (isNaN(date.getTime())) { next[field.name] = `${field.label} is not a valid date`; } else if (date > new Date()) { next[field.name] = `${field.label} cannot be in the future`; } } } }); setErrors(next); return Object.keys(next).length === 0; }; const handleSubmit = () => { if (!validate()) return; const payload = Object.fromEntries( Object.entries(values) .map(([key, value]) => { if (value === FLEET_SELECT_NONE || value === "") return [key, undefined]; return [key, value]; }) .filter(([, value]) => value !== undefined), ); onSubmit(payload); }; const renderField = (field: FleetFormFieldDef) => { const value = values[field.name]; const error = errors[field.name]; if (field.type === "select") { return (