/** * @ai-summary Dialog for editing maintenance schedules * @ai-context Modal form following MaintenanceRecordEditDialog pattern */ import React, { useState, useEffect } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Box, Grid, FormControl, InputLabel, Select, MenuItem, Typography, useMediaQuery, FormControlLabel, Switch, RadioGroup, Radio, FormLabel, } from '@mui/material'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import dayjs from 'dayjs'; import { MaintenanceScheduleResponse, UpdateScheduleRequest, MaintenanceCategory, ScheduleType, getCategoryDisplayName, } from '../types/maintenance.types'; import { SubtypeCheckboxGroup } from './SubtypeCheckboxGroup'; import { useVehicles } from '../../vehicles/hooks/useVehicles'; import type { Vehicle } from '../../vehicles/types/vehicles.types'; import { getVehicleLabel } from '@/core/utils/vehicleDisplay'; interface MaintenanceScheduleEditDialogProps { open: boolean; schedule: MaintenanceScheduleResponse | null; onClose: () => void; onSave: (id: string, data: UpdateScheduleRequest) => Promise; } export const MaintenanceScheduleEditDialog: React.FC = ({ open, schedule, onClose, onSave, }) => { const [formData, setFormData] = useState({}); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const vehiclesQuery = useVehicles(); const vehicles = vehiclesQuery.data; const isSmallScreen = useMediaQuery('(max-width:600px)'); // Reset form when schedule changes useEffect(() => { if (schedule && schedule.id) { try { setFormData({ category: schedule.category, subtypes: schedule.subtypes, scheduleType: schedule.scheduleType, intervalMonths: schedule.intervalMonths || undefined, intervalMiles: schedule.intervalMiles || undefined, fixedDueDate: schedule.fixedDueDate || undefined, isActive: schedule.isActive, emailNotifications: schedule.emailNotifications || false, reminderDays1: schedule.reminderDays1 || undefined, reminderDays2: schedule.reminderDays2 || undefined, reminderDays3: schedule.reminderDays3 || undefined, }); setError(null); } catch (err) { console.error('[MaintenanceScheduleEditDialog] Error setting form data:', err); setError(err as Error); } } }, [schedule]); const handleInputChange = (field: keyof UpdateScheduleRequest, value: any) => { setFormData((prev) => ({ ...prev, [field]: value, })); }; const handleScheduleTypeChange = (newType: ScheduleType) => { setFormData((prev) => { const updated: UpdateScheduleRequest = { ...prev, scheduleType: newType, }; // Clear fields that don't apply to new schedule type if (newType === 'interval') { updated.fixedDueDate = null; } else if (newType === 'fixed_date') { updated.intervalMonths = null; updated.intervalMiles = null; } else if (newType === 'time_since_last') { updated.fixedDueDate = null; } return updated; }); }; const handleSave = async () => { if (!schedule || !schedule.id) { console.error('[MaintenanceScheduleEditDialog] No valid schedule to save'); return; } try { setIsSaving(true); // Filter out unchanged fields const changedData: UpdateScheduleRequest = {}; Object.entries(formData).forEach(([key, value]) => { const typedKey = key as keyof UpdateScheduleRequest; const scheduleValue = schedule[typedKey as keyof MaintenanceScheduleResponse]; // Special handling for arrays if (Array.isArray(value) && Array.isArray(scheduleValue)) { if (JSON.stringify(value) !== JSON.stringify(scheduleValue)) { (changedData as any)[key] = value; } } else if (value !== scheduleValue) { (changedData as any)[key] = value; } }); // Only send update if there are actual changes if (Object.keys(changedData).length > 0) { await onSave(schedule.id, changedData); } onClose(); } catch (err) { console.error('[MaintenanceScheduleEditDialog] Failed to save schedule:', err); setError(err as Error); } finally { setIsSaving(false); } }; const handleCancel = () => { onClose(); }; // Early bailout if dialog not open or no schedule to edit if (!open || !schedule) return null; // Error state if (error) { return ( Error Loading Maintenance Schedule Failed to load maintenance schedule data. Please try again. {error.message} ); } const currentScheduleType = formData.scheduleType || 'interval'; return ( Edit Maintenance Schedule {/* Vehicle (Read-only display) */} { const vehicle = vehicles?.find((v: Vehicle) => v.id === schedule.vehicleId); return getVehicleLabel(vehicle); })()} helperText="Vehicle cannot be changed when editing" /> {/* Active Status */} handleInputChange('isActive', e.target.checked)} /> } label="Schedule is active" /> Inactive schedules will not trigger reminders {/* Category */} Category {/* Subtypes */} {formData.category && ( Service Types * handleInputChange('subtypes', subtypes)} /> )} {/* Schedule Type */} Schedule Type handleScheduleTypeChange(e.target.value as ScheduleType)} > } label="Interval-based (months or miles)" /> } label="Fixed due date" /> } label="Time since last service" /> {/* Interval-based fields */} {currentScheduleType === 'interval' && ( <> handleInputChange( 'intervalMonths', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Service every X months" inputProps={{ min: 1 }} /> handleInputChange( 'intervalMiles', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Service every X miles" inputProps={{ min: 1 }} /> )} {/* Fixed date field */} {currentScheduleType === 'fixed_date' && ( handleInputChange('fixedDueDate', newValue?.format('YYYY-MM-DD') || undefined) } format="MM/DD/YYYY" slotProps={{ textField: { fullWidth: true, helperText: 'One-time service due date', sx: { '& .MuiOutlinedInput-root': { minHeight: '56px', }, }, }, }} /> )} {/* Time since last fields */} {currentScheduleType === 'time_since_last' && ( <> handleInputChange( 'intervalMonths', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Months after last service" inputProps={{ min: 1 }} /> handleInputChange( 'intervalMiles', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Miles after last service" inputProps={{ min: 1 }} /> )} {/* Email Notifications */} handleInputChange('emailNotifications', e.target.checked)} /> } label="Email notifications" /> {/* Reminder Days (only if email notifications enabled) */} {formData.emailNotifications && ( <> Reminder Days Before Due Date handleInputChange( 'reminderDays1', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Days before" inputProps={{ min: 1 }} /> handleInputChange( 'reminderDays2', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Days before" inputProps={{ min: 1 }} /> handleInputChange( 'reminderDays3', e.target.value ? parseInt(e.target.value) : undefined ) } helperText="Days before" inputProps={{ min: 1 }} /> )} ); };