/** * @ai-summary Form component for adding/editing ownership costs */ import React, { useState, useEffect } from 'react'; import { Button } from '../../../shared-minimal/components/Button'; import { OwnershipCost, OwnershipCostType, CostInterval, COST_TYPE_LABELS, INTERVAL_LABELS } from '../types/ownership-costs.types'; interface OwnershipCostFormProps { vehicleId: string; initialData?: OwnershipCost; onSubmit: (data: { costType: OwnershipCostType; description?: string; amount: number; interval: CostInterval; startDate: string; endDate?: string; }) => Promise; onCancel: () => void; loading?: boolean; } export const OwnershipCostForm: React.FC = ({ initialData, onSubmit, onCancel, loading, }) => { const [costType, setCostType] = useState(initialData?.costType || 'insurance'); const [description, setDescription] = useState(initialData?.description || ''); const [amount, setAmount] = useState(initialData?.amount?.toString() || ''); const [interval, setInterval] = useState(initialData?.interval || 'monthly'); const [startDate, setStartDate] = useState(initialData?.startDate || new Date().toISOString().split('T')[0]); const [endDate, setEndDate] = useState(initialData?.endDate || ''); const [error, setError] = useState(null); useEffect(() => { if (initialData) { setCostType(initialData.costType); setDescription(initialData.description || ''); setAmount(initialData.amount.toString()); setInterval(initialData.interval); setStartDate(initialData.startDate); setEndDate(initialData.endDate || ''); } }, [initialData]); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); // Validate amount const parsedAmount = parseFloat(amount); if (isNaN(parsedAmount) || parsedAmount < 0) { setError('Please enter a valid amount'); return; } // Validate dates if (!startDate) { setError('Start date is required'); return; } if (endDate && new Date(endDate) < new Date(startDate)) { setError('End date must be after start date'); return; } try { await onSubmit({ costType, description: description.trim() || undefined, amount: parsedAmount, interval, startDate, endDate: endDate || undefined, }); } catch (err: unknown) { const message = err instanceof Error ? err.message : 'Failed to save cost'; setError(message); } }; const isEditMode = !!initialData; return (
{error && (
{error}
)}
setDescription(e.target.value)} placeholder="e.g., Geico Full Coverage" className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna" style={{ fontSize: '16px' }} />
setAmount(e.target.value)} placeholder="0.00" inputMode="decimal" step="0.01" min="0" required className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone dark:placeholder-canna" style={{ fontSize: '16px' }} />
setStartDate(e.target.value)} required className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone" style={{ fontSize: '16px' }} />
setEndDate(e.target.value)} className="w-full px-3 py-2 border rounded-md min-h-[44px] bg-white text-gray-900 border-gray-300 focus:outline-none focus:ring-2 focus:ring-primary-500 dark:bg-scuro dark:text-avus dark:border-silverstone" style={{ fontSize: '16px' }} />

Leave blank for ongoing costs

); };