import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPlus, faTrash } from '@fortawesome/pro-duotone-svg-icons'; import { Input } from '@/components/base/input/input'; import { Select } from '@/components/base/select/select'; import { Toggle } from '@/components/base/toggle/toggle'; import { Button } from '@/components/base/buttons/button'; import { TimePicker } from '@/components/application/date-picker/time-picker'; // Doctor form — hospital-wide profile with multi-clinic, multi-day // visiting schedule. Each row in the "visiting schedule" section maps // to one DoctorVisitSlot child record. The parent component owns the // mutation orchestration (create doctor, then create each slot). // // Previously the form had a single `clinicId` dropdown + a free-text // `visitingHours` textarea. Both dropped — doctors are now hospital- // wide, and their presence at each clinic is expressed via the // DoctorVisitSlot records. export type DoctorDepartment = | 'CARDIOLOGY' | 'GYNECOLOGY' | 'ORTHOPEDICS' | 'GENERAL_MEDICINE' | 'ENT' | 'DERMATOLOGY' | 'PEDIATRICS' | 'ONCOLOGY'; // Matches the DoctorVisitSlot.dayOfWeek SELECT enum on the SDK entity. export type DayOfWeek = | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY' | 'SUNDAY'; export type DoctorVisitSlotEntry = { // Populated on existing records when editing; undefined for // freshly-added rows. Used by the parent to decide create vs // update vs delete on save. id?: string; clinicId: string; dayOfWeek: DayOfWeek | ''; startTime: string | null; endTime: string | null; }; export type DoctorFormValues = { firstName: string; lastName: string; department: DoctorDepartment | ''; specialty: string; qualifications: string; yearsOfExperience: string; consultationFeeNew: string; consultationFeeFollowUp: string; phone: string; email: string; registrationNumber: string; active: boolean; // Multi-clinic, multi-day visiting schedule. One entry per slot. visitSlots: DoctorVisitSlotEntry[]; }; export const emptyDoctorFormValues = (): DoctorFormValues => ({ firstName: '', lastName: '', department: '', specialty: '', qualifications: '', yearsOfExperience: '', consultationFeeNew: '', consultationFeeFollowUp: '', phone: '', email: '', registrationNumber: '', active: true, visitSlots: [], }); const DEPARTMENT_ITEMS: { id: DoctorDepartment; label: string }[] = [ { id: 'CARDIOLOGY', label: 'Cardiology' }, { id: 'GYNECOLOGY', label: 'Gynecology' }, { id: 'ORTHOPEDICS', label: 'Orthopedics' }, { id: 'GENERAL_MEDICINE', label: 'General medicine' }, { id: 'ENT', label: 'ENT' }, { id: 'DERMATOLOGY', label: 'Dermatology' }, { id: 'PEDIATRICS', label: 'Pediatrics' }, { id: 'ONCOLOGY', label: 'Oncology' }, ]; const DAY_ITEMS: { id: DayOfWeek; label: string }[] = [ { id: 'MONDAY', label: 'Monday' }, { id: 'TUESDAY', label: 'Tuesday' }, { id: 'WEDNESDAY', label: 'Wednesday' }, { id: 'THURSDAY', label: 'Thursday' }, { id: 'FRIDAY', label: 'Friday' }, { id: 'SATURDAY', label: 'Saturday' }, { id: 'SUNDAY', label: 'Sunday' }, ]; // Build the createDoctor / updateDoctor mutation payload. Visit slots // are persisted via a separate mutation chain — see the parent // component's handleSave. export const doctorCoreToGraphQLInput = (v: DoctorFormValues): Record => { const input: Record = { fullName: { firstName: v.firstName.trim(), lastName: v.lastName.trim(), }, active: v.active, }; if (v.department) input.department = v.department; if (v.specialty.trim()) input.specialty = v.specialty.trim(); if (v.qualifications.trim()) input.qualifications = v.qualifications.trim(); if (v.yearsOfExperience.trim()) { const n = Number(v.yearsOfExperience); if (!Number.isNaN(n)) input.yearsOfExperience = n; } if (v.consultationFeeNew.trim()) { const n = Number(v.consultationFeeNew); if (!Number.isNaN(n)) { input.consultationFeeNew = { amountMicros: Math.round(n * 1_000_000), currencyCode: 'INR', }; } } if (v.consultationFeeFollowUp.trim()) { const n = Number(v.consultationFeeFollowUp); if (!Number.isNaN(n)) { input.consultationFeeFollowUp = { amountMicros: Math.round(n * 1_000_000), currencyCode: 'INR', }; } } if (v.phone.trim()) { input.phone = { primaryPhoneNumber: v.phone.trim(), primaryPhoneCountryCode: 'IN', primaryPhoneCallingCode: '+91', additionalPhones: null, }; } if (v.email.trim()) { input.email = { primaryEmail: v.email.trim(), additionalEmails: null, }; } if (v.registrationNumber.trim()) input.registrationNumber = v.registrationNumber.trim(); return input; }; // Build one DoctorVisitSlotCreateInput per complete slot. Drops any // half-filled rows silently — the form can't validate mid-entry // without blocking the user. export const visitSlotInputsFromForm = ( v: DoctorFormValues, doctorId: string, ): Array> => v.visitSlots .filter((s) => s.clinicId && s.dayOfWeek && s.startTime && s.endTime) .map((s) => ({ doctorId, clinicId: s.clinicId, dayOfWeek: s.dayOfWeek, startTime: s.startTime, endTime: s.endTime, })); type ClinicOption = { id: string; label: string }; type DoctorFormProps = { value: DoctorFormValues; onChange: (value: DoctorFormValues) => void; clinics: ClinicOption[]; }; export const DoctorForm = ({ value, onChange, clinics }: DoctorFormProps) => { const patch = (updates: Partial) => onChange({ ...value, ...updates }); // Visit-slot handlers — add/edit/remove inline inside the form. const addSlot = () => { patch({ visitSlots: [ ...value.visitSlots, { clinicId: clinics[0]?.id ?? '', dayOfWeek: '', startTime: '09:00', endTime: '13:00' }, ], }); }; const updateSlot = (index: number, updates: Partial) => { const next = [...value.visitSlots]; next[index] = { ...next[index], ...updates }; patch({ visitSlots: next }); }; const removeSlot = (index: number) => { patch({ visitSlots: value.visitSlots.filter((_, i) => i !== index) }); }; return (
patch({ firstName: v })} /> patch({ lastName: v })} />
patch({ specialty: v })} />
patch({ qualifications: v })} /> patch({ yearsOfExperience: v })} />
{/* Visiting schedule — one row per clinic/day slot */}

Visiting schedule

{clinics.length === 0 ? (

Add a clinic first

You need at least one clinic before you can schedule doctor visits.

) : ( <> {value.visitSlots.length === 0 && (

No visit slots. Add rows for each clinic + day this doctor visits.

)} {value.visitSlots.map((slot, idx) => (
updateSlot(idx, { startTime })} /> updateSlot(idx, { endTime })} />
))} )}
patch({ consultationFeeNew: v })} /> patch({ consultationFeeFollowUp: v })} />

Contact

patch({ phone: v })} /> patch({ email: v })} /> patch({ registrationNumber: v })} />
patch({ active: checked })} />

Inactive doctors are hidden from appointment booking and call-desk transfer lists.

); };