import React from 'react'; import Box from '@mui/material/Box'; import TextField from '@mui/material/TextField'; import FormControl from '@mui/material/FormControl'; import FormLabel from '@mui/material/FormLabel'; import FormControlLabel from '@mui/material/FormControlLabel'; import RadioGroup from '@mui/material/RadioGroup'; import Radio from '@mui/material/Radio'; import IconButton from '@mui/material/IconButton'; import CloseIcon from '@mui/icons-material/Close'; import type { SxProps, Theme } from '@mui/material/styles'; import { WizardLayout } from '../../templates/WizardLayout'; import { Input } from '../../atoms/Input'; import { Collapse } from '../../atoms/Collapse'; import { Typography } from '../../atoms/Typography'; import { Button } from '../../atoms/Button'; import { Link } from '../../atoms/Link'; import { Divider } from '../../atoms/Divider'; // ─── Types ─────────────────────────────────────────────────────────────────── /** Funeral date preference */ export type FuneralDatePref = 'asap' | 'specific' | null; /** Time-of-day preference */ export type FuneralTimePref = 'no_preference' | 'morning' | 'midday' | 'afternoon' | 'evening'; /** Form values for the date/time step */ export interface DateTimeStepValues { /** Deceased first name */ firstName: string; /** Deceased surname */ surname: string; /** Date preference (ASAP or specific) */ funeralDate: FuneralDatePref; /** Preferred dates (up to 3) when funeralDate is "specific" */ preferredDates: string[]; /** Time-of-day preference */ funeralTime: FuneralTimePref; } /** Field-level error messages */ export interface DateTimeStepErrors { firstName?: string; surname?: string; funeralDate?: string; preferredDates?: string; } /** Props for the DateTimeStep page component */ export interface DateTimeStepProps { /** Current form values */ values: DateTimeStepValues; /** Callback when any field value changes */ onChange: (values: DateTimeStepValues) => void; /** Callback when the Continue button is clicked */ onContinue: () => void; /** Callback for back navigation */ onBack?: () => void; /** Callback for save-and-exit */ onSaveAndExit?: () => void; /** Field-level validation errors */ errors?: DateTimeStepErrors; /** Whether the Continue button is in a loading state */ loading?: boolean; /** Whether the person has passed (at-need) or is alive (pre-planning) */ isAtNeed?: boolean; /** Whether deceased name fields should be shown */ showNameFields?: boolean; /** Whether scheduling fields should be shown */ showScheduling?: boolean; /** Navigation bar — passed through to WizardLayout */ navigation?: React.ReactNode; /** Hide the help bar */ hideHelpBar?: boolean; /** MUI sx prop for the root */ sx?: SxProps; } // ─── Constants ─────────────────────────────────────────────────────────────── const MAX_PREFERRED_DATES = 3; const DATE_LABELS = ['First preference', 'Second preference', 'Third preference']; // ─── Component ─────────────────────────────────────────────────────────────── /** * Step 6 — Details & Scheduling for the FA arrangement wizard. * * Captures deceased details (name) and funeral date/time preferences. * Two logical sections: "About the person" and "Service timing". * Each wrapped in fieldset/legend for screen reader structure. * * Date preferences support up to 3 preferred dates via progressive * disclosure ("+ Add another date" link). * * Service tradition (religion) is NOT captured here — it flows through * from provider/package selection and is confirmed on the summary step. * * Grief-sensitive labels: "Their first name" not "Deceased First Name". * * Pure presentation component — props in, callbacks out. * * Spec: documentation/steps/steps/06_date_time.yaml */ export const DateTimeStep: React.FC = ({ values, onChange, onContinue, onBack, onSaveAndExit, errors, loading = false, isAtNeed = true, showNameFields = true, showScheduling = true, navigation, hideHelpBar, sx, }) => { const handleFieldChange = ( field: K, value: DateTimeStepValues[K], ) => { onChange({ ...values, [field]: value }); }; const handleDateChange = (index: number, value: string) => { const next = [...values.preferredDates]; next[index] = value; onChange({ ...values, preferredDates: next }); }; const handleAddDate = () => { if (values.preferredDates.length < MAX_PREFERRED_DATES) { onChange({ ...values, preferredDates: [...values.preferredDates, ''] }); } }; const handleRemoveDate = (index: number) => { const next = values.preferredDates.filter((_, i) => i !== index); onChange({ ...values, preferredDates: next.length === 0 ? [''] : next }); }; const personSectionHeading = isAtNeed ? 'About the person who has passed' : 'About the person'; const schedulingHeading = isAtNeed ? 'When are you hoping to have the service?' : 'When would you like the service?'; const minDate = new Date().toISOString().split('T')[0]; return ( {/* Page heading */} A few important details {isAtNeed ? 'We just need a few details to help arrange the service.' : "If you're not sure about dates yet, that's fine. You can update this later."} { e.preventDefault(); if (!loading) onContinue(); }} > {/* ─── Section 1: About the person ─── */} {showNameFields && ( {personSectionHeading} handleFieldChange('firstName', e.target.value)} error={!!errors?.firstName} helperText={errors?.firstName} autoComplete="off" fullWidth required /> handleFieldChange('surname', e.target.value)} error={!!errors?.surname} helperText={errors?.surname} autoComplete="off" fullWidth required /> )} {showNameFields && showScheduling && } {/* ─── Section 2: Scheduling ─── */} {showScheduling && ( {schedulingHeading} {/* Date preference */} Preferred timing { const pref = e.target.value as FuneralDatePref; onChange({ ...values, funeralDate: pref, // Initialise with one empty date slot when switching to specific preferredDates: pref === 'specific' && values.preferredDates.length === 0 ? [''] : values.preferredDates, }); }} > } label="As soon as possible" sx={{ mb: 0.5 }} /> } label="I have a preferred date" /> {/* Preferred dates — progressive disclosure, up to 3 */} {values.preferredDates.map((date, index) => ( handleDateChange(index, e.target.value)} error={index === 0 && !!errors?.preferredDates} helperText={index === 0 ? errors?.preferredDates : undefined} InputLabelProps={{ shrink: true }} inputProps={{ min: minDate }} fullWidth required={index === 0} /> {index > 0 && ( handleRemoveDate(index)} aria-label={`Remove ${DATE_LABELS[index]?.toLowerCase() ?? 'date'}`} sx={{ mt: 1, color: 'text.secondary' }} > )} ))} {values.preferredDates.length < MAX_PREFERRED_DATES && ( + Add another date )} {/* Time-of-day preference */} Do you have a preferred time of day? handleFieldChange('funeralTime', e.target.value as FuneralTimePref) } > } label="No preference" sx={{ mb: 0.5 }} /> } label="Morning" sx={{ mb: 0.5 }} /> } label="Midday" sx={{ mb: 0.5 }} /> } label="Afternoon" sx={{ mb: 0.5 }} /> } label="Evening" /> )} {/* CTAs */} {onSaveAndExit ? ( ) : ( )} ); }; DateTimeStep.displayName = 'DateTimeStep'; export default DateTimeStep;