import React, { useState, useEffect, useCallback } from 'react'; import { Flex, FlexItem } from '../components/ui/flex'; import { DismissibleAlert } from '../components/ui/dismissible-alert'; import { Modal } from '../components/ui/wp-modal-shim'; import { useForm, FormProvider } from 'react-hook-form'; import { HealthcareService, Organization, Attachment } from 'fhir/r4'; import { useHealthcareServiceServiceContext, useAuthServiceContext, useValueSetServiceContext } from '../services'; import { FhirHealthcareService } from '../components'; import { useFhirHealthcareServiceTargetedBroadcast } from '../hooks'; import { preserveHealthcareServiceExtensions } from '../config/healthcareServiceExtensions'; import { describeWriteFailure } from '../utils/fetchFailureMessage'; import { invalidSubmitMessage } from '../utils/forms/invalidSubmitMessage'; import { defaultHoursRows } from '../utils/defaultHoursRows'; interface HealthcareServiceModalProps { isOpen: boolean; onClose: () => void; healthcareService?: HealthcareService; onSuccess?: (healthcareService: HealthcareService) => void; onError?: (error: string) => void; title?: string; } export const HealthcareServiceModal: React.FC = ({ isOpen, onClose, healthcareService, onSuccess, onError, title }) => { const { wpOrganization } = useAuthServiceContext(); const { daysOfWeek } = useValueSetServiceContext(); const { transformToFhirHealthcareService, transformFromFhirHealthcareService, createHealthcareService, updateHealthcareService } = useHealthcareServiceServiceContext(); const [submitting, setSubmitting] = useState(false); const [success, setSuccess] = useState(); const [error, setError] = useState(); const [photo, setPhoto] = useState(); const isNew = !healthcareService; const modalTitle = title || `${isNew ? 'Create' : 'Edit'} Healthcare Service`; const methods = useForm({ defaultValues: { active: true, name: '', comment: '', extraDetails: '', category: [], type: [], specialty: [], location: [], coverageArea: [], serviceProvisionCode: [], eligibility: [], program: [], characteristic: [], communication: [], referralMethod: [], appointmentRequired: false, availabilityExceptions: '', availableTime: defaultHoursRows(daysOfWeek), notAvailable: [], telecom: [], endpoint: [], photo: null, identifier: [] } }); const { handleSubmit, reset } = methods; // A REFUSED CLICK SAYS SO WHERE IT HAPPENED. The button is in the modal header, above a form that // can be several screens tall, and react-hook-form reports each problem inline beside its field - // so somebody scrolled past the first card saw nothing change at all. This fills the error slot // this modal already has, at the top of the form, next to the button they pressed. const onInvalid = (errors: unknown) => setError(invalidSubmitMessage(errors)); const init = useCallback((healthcareService: HealthcareService) => { const { photo: healthcareServicePhoto, formData } = transformFromFhirHealthcareService(healthcareService); reset(formData); setPhoto(healthcareServicePhoto); }, [transformFromFhirHealthcareService, reset]); useFhirHealthcareServiceTargetedBroadcast({ healthcareService, isOpen, onUpdate: init, onDelete: onClose }); useEffect(() => { if (healthcareService) { init(healthcareService); } }, [healthcareService, init]); const handlePhotoChange = (newPhoto: Attachment | undefined) => { setPhoto(newPhoto); }; const onSubmit = async (data: any) => { if (!wpOrganization.current) { const errorMsg = 'Organization information is missing. Please try again.'; setError(errorMsg); onError?.(errorMsg); return; } setSubmitting(true); setSuccess(undefined); setError(undefined); try { let result: HealthcareService; if (isNew) { result = await createHealthcareService(transformToFhirHealthcareService(data, photo, wpOrganization.current as Organization)); } else { // The transform emits no `extension`; carry the existing service's extensions // (duration, self-bookable, price) through so this edit doesn't wipe them. result = await updateHealthcareService( preserveHealthcareServiceExtensions( { id: healthcareService?.id, ...transformToFhirHealthcareService(data, photo) }, healthcareService ) ); } const successMsg = `Healthcare service ${isNew ? 'created' : 'updated'} successfully.`; setSuccess(successMsg); onSuccess?.(result); setTimeout(() => { setSuccess(undefined); onClose(); }, 1500); } catch (err: any) { console.error(`Error ${isNew ? 'creating' : 'updating'} healthcare service:`, err); const errorMsg = describeWriteFailure(err, `Failed to ${isNew ? 'create' : 'update'} healthcare service`); setError(errorMsg); onError?.(errorMsg); } finally { setSubmitting(false); } }; if (!isOpen) return null; return ( ]} >
{success && ( setSuccess(undefined)} className="mb-4"> {success} )} {error && ( setError(undefined)} className="mb-4"> {error} )}
); };