/** * Default shipping form: owns state, validation (Zod), and errors. * Notifies page via onChange(formId, value) and onInteraction(). */ import { __ } from '@wordpress/i18n'; import { memo, useState, useEffect, useCallback, useRef, } from '@wordpress/element'; import { Flex } from '@wordpress/components'; import { SettingsField } from './settings-field'; import type { DefaultShippingSettings } from '../../types/settings'; import type { SettingsFieldSelectOption } from './settings-field'; import { defaultShippingSchema } from './utils/schemas'; import { getSectionFieldErrors } from './utils/getSettingsFieldErrors'; export const SHIPPING_FORM_ID = 'shipping' as const; export interface DefaultShippingFormProps { defaultValue: DefaultShippingSettings; onChange: (formId: string, value: DefaultShippingSettings) => void; onInteraction?: () => void; resetTrigger?: number; submitErrors?: Record; countryOptions: SettingsFieldSelectOption[]; countriesLoading?: boolean; } function DefaultShippingFormInner({ defaultValue, onChange, onInteraction, resetTrigger = 0, submitErrors, countryOptions, countriesLoading = false, }: DefaultShippingFormProps) { const [value, setValue] = useState(() => ({ ...defaultValue, })); const [errors, setErrors] = useState>({}); const hasInteracted = useRef(false); // Reset to default when page triggers discard or default changes. useEffect(() => { setValue({ ...defaultValue }); setErrors({}); hasInteracted.current = false; }, [resetTrigger, defaultValue]); const displayErrors = submitErrors ?? errors; const handleChange = useCallback( (field: keyof DefaultShippingSettings, v: string) => { if (!hasInteracted.current) { hasInteracted.current = true; onInteraction?.(); } const next = { ...value, [field]: v }; const result = defaultShippingSchema.safeParse(next); // All setState calls together, outside any updater setValue(next); setErrors( result.success ? {} : getSectionFieldErrors(result.error) ); onChange(SHIPPING_FORM_ID, next); }, [value, onChange, onInteraction] ); return ( handleChange('contactName', v)} error={displayErrors.contactName} required /> handleChange('organisation', v)} error={displayErrors.organisation} /> handleChange('property', v)} error={displayErrors.property} required /> handleChange('street', v)} error={displayErrors.street} required /> handleChange('town', v)} error={displayErrors.town} required /> handleChange('postcode', v)} error={displayErrors.postcode} required /> handleChange('county', v)} error={displayErrors.county} /> handleChange('country', v)} options={countryOptions} error={displayErrors.country} disabled={countriesLoading} required /> handleChange('email', v)} type="email" error={displayErrors.email} required /> handleChange('phone', v)} error={displayErrors.phone} required /> ); } export const DefaultShippingForm = memo(DefaultShippingFormInner);