import type { BookabilityBlocker } from './bookabilityReasons'; import { sortBlockers } from './bookabilityReasons'; // Would the schedule block you are about to save be bookable by a patient? // // WHY THIS IS NOT resolveBookability. This runs BEFORE the save, against the FORM values - there is no // persisted Schedule resource to resolve yet, and building a synthetic one here would mean duplicating the // modal's formFHIR transform, which is a worse duplication than this is. // // The containment rule that keeps it honest: this may only ever emit codes from the SHARED // BookabilityBlocker vocabulary, and its copy comes from the shared bookabilityCopy module. It is a strict // subset of what the resolver can say - never a competing opinion, and never a new vocabulary. // // It also cannot see everything the resolver can (a service switched off org-wide, a deactivated role), so an // empty result means "nothing obviously wrong from here", NOT "guaranteed bookable". The warning is worded // accordingly and never blocks a save. export interface ScheduleFormValues { serviceIds?: string[]; allowBooking?: boolean; allowPatientSelfBooking?: boolean; availableTime?: unknown[]; planningHorizon?: { start?: string; end?: string }; } export function shouldWarnBeforeSave(form: ScheduleFormValues): BookabilityBlocker[] { const blockers: BookabilityBlocker[] = []; if ((form.serviceIds ?? []).length === 0) blockers.push('BLOCK_DOES_NOT_OFFER_SERVICE'); // Defaults are permissive, matching getScheduleBookingFlags: absent allowed. if (form.allowBooking === false) blockers.push('BLOCK_BOOKING_DISABLED'); if (form.allowPatientSelfBooking === false) blockers.push('BLOCK_SELF_BOOKING_DISABLED'); if ((form.availableTime ?? []).length === 0) blockers.push('BLOCK_NO_HOURS'); if (!form.planningHorizon?.start || !form.planningHorizon?.end) { blockers.push('BLOCK_NO_PLANNING_HORIZON'); } return sortBlockers(blockers); }