/** * - A BLOCK WHOSE ONLY PLACE IS THE VIRTUAL ONE IS A MODALITY, NOT A SITE. * * Telehealth is a Location on this project, so a diary block offered only at the org's virtual * Location can be booked one way and one way only: by video. Choosing that block IS choosing video, * before the Location control is ever touched. * * WHY THIS MATTERS AT THE PICKER. The server gates a video booking three ways - the practice offers * video, the block offers it, and the service is marked deliverable by video (default not) - and the * third is the one the front desk met as a refusal at the end of a filled-in form: * * ERROR: This service cannot be delivered by video. Please book it in person, or contact the practice. * * Measured at the desk on 2026-09-13: the picker offered exactly one practitioner for a follow-up * consultation, "Dr. Practitioner One - Video Visit", and it was the one option that could never be * booked. The gate is correct and load-bearing; the list was not applying it. * * `every` rather than `includes`: a block offered at a site AND by video is a real choice between the * two, and the Location control is where that choice is made. This names only the block that leaves * no choice at all. An empty list is not video-only either - that is a role scoped to every site. */ export const blockIsVideoOnly = ( locationIds: readonly (string | undefined)[], virtualLocationId: string | undefined, ): boolean => !!virtualLocationId && locationIds.length > 0 && locationIds.every((id) => id === virtualLocationId); /** * The server's own two sentences, on the row instead of after the booking. * * Kept as the reason a row is disabled rather than as a refusal, because the rule they state is the * practice's configuration and not a fault: a receptionist reading either one knows what to change, * or knows to book the visit in person. */ export const VIDEO_ONLY_SERVICE_INELIGIBLE = 'this service cannot be delivered by video'; export const VIDEO_ONLY_PRACTICE_DISABLED = 'this practice does not offer video visits';