import { useCallback, useEffect, useMemo, useState } from 'react'; import { WizardStep } from './wizard-step'; import { DoctorsRightPane, type DoctorSummary } from './wizard-right-panes'; import { DoctorForm, doctorCoreToGraphQLInput, visitSlotInputsFromForm, emptyDoctorFormValues, type DoctorFormValues, } from '@/components/forms/doctor-form'; import { apiClient } from '@/lib/api-client'; import { notify } from '@/lib/toast'; import type { WizardStepComponentProps } from './wizard-step-types'; // Doctor step — mirrors the clinics step but also fetches the clinic list // for the DoctorForm's clinic dropdown. If there are no clinics yet we let // the admin know they need to complete step 2 first (the wizard doesn't // force ordering, but a doctor without a clinic is useless). type ClinicLite = { id: string; clinicName: string | null }; export const WizardStepDoctors = (props: WizardStepComponentProps) => { const [values, setValues] = useState(emptyDoctorFormValues); const [clinics, setClinics] = useState([]); const [doctors, setDoctors] = useState([]); const [loadingClinics, setLoadingClinics] = useState(true); const [saving, setSaving] = useState(false); const fetchData = useCallback(async () => { try { const data = await apiClient.graphql<{ clinics: { edges: { node: ClinicLite }[] }; doctors: { edges: { node: DoctorSummary }[] }; }>( `{ clinics(first: 100) { edges { node { id clinicName } } } doctors(first: 100, orderBy: { createdAt: DescNullsLast }) { edges { node { id fullName { firstName lastName } department specialty } } } }`, undefined, { silent: true }, ); setClinics(data.clinics.edges.map((e) => e.node)); setDoctors(data.doctors.edges.map((e) => e.node)); } catch (err) { console.error('[wizard/doctors] fetch failed', err); setClinics([]); setDoctors([]); } finally { setLoadingClinics(false); } }, []); useEffect(() => { fetchData(); }, [fetchData]); const clinicOptions = useMemo( () => clinics.map((c) => ({ id: c.id, label: c.clinicName ?? 'Unnamed clinic' })), [clinics], ); const handleSave = async () => { if (!values.firstName.trim() || !values.lastName.trim()) { notify.error('First and last name are required'); return; } setSaving(true); try { // 1. Core doctor record const res = await apiClient.graphql<{ createDoctor: { id: string } }>( `mutation CreateDoctor($data: DoctorCreateInput!) { createDoctor(data: $data) { id } }`, { data: doctorCoreToGraphQLInput(values) }, ); const doctorId = res.createDoctor.id; // 2. Visit slots (doctor can be at multiple clinics on // multiple days with different times each). const slotInputs = visitSlotInputsFromForm(values, doctorId); if (slotInputs.length > 0) { await Promise.all( slotInputs.map((data) => apiClient.graphql( `mutation CreateDoctorVisitSlot($data: DoctorVisitSlotCreateInput!) { createDoctorVisitSlot(data: $data) { id } }`, { data }, ), ), ); } notify.success('Doctor added', `Dr. ${values.firstName} ${values.lastName}`); await fetchData(); if (!props.isCompleted) { await props.onComplete('doctors'); } setValues(emptyDoctorFormValues()); } catch (err) { console.error('[wizard/doctors] save failed', err); } finally { setSaving(false); } }; const pretendCompleted = props.isCompleted || doctors.length > 0; return ( } > {loadingClinics ? (

Loading clinics…

) : clinics.length === 0 ? (

Add a clinic first

You need at least one clinic before you can assign doctors. Go back to the{' '} Clinics step and add a branch first.

) : ( <>
)}
); };