import type { Practitioner, PractitionerRole } from 'fhir/r4'; /** * WHOSE SCHEDULE DOES "MANAGE SCHEDULE" OPEN ON? -. * * Extracted from the schedules page because the answer is a PERMISSION decision, and it was previously * spread across two JSX conditions forty lines apart. Each was correct alone. Together they closed on * each other, and nothing anywhere asserted the path between them. * * WHAT WENT WRONG * The `schedules` section takes a level AND a scope, so a role can be given **manage your own only**. * At that scope the staff picker is withdrawn on purpose ( - do not offer a list this reader can * never load), and the manage control only rendered once somebody had been SELECTED. The only remaining * route was typing your own name into the search box, which is built from the schedule list plus the * staff directory - **both empty for somebody who has no schedule yet.** * * **The person told they may manage their own hours could not reach the control that creates them**, * and the state they were stuck in is exactly the state the grant was given to fix. It failed in the * quiet direction: no error, no refusal, a true-sounding notice and a true-sounding empty calendar. * * WHAT THIS IS NOT * **Not a widening.** It never chooses a person; it recognises that at `own` scope there is only ever one * person this control could mean, and names them. The GRANT is decided elsewhere and unchanged - the page * still gates the control on `canManage('schedules')`, so a view-only role gains nothing. * * And not "unhide the picker". That would hand a manage-own reader a list of colleagues they may not * manage, which is the exact control removed. **The scope is right; the entry was missing.** */ export interface ScheduleManageTarget { practitioner: Practitioner; /** The target's PractitionerRoles, already narrowed to the current organization by the caller. */ roles: PractitionerRole[]; /** True when this resolved to the reader themselves rather than to an explicit selection. */ isOwn: boolean; } export interface ScheduleManageTargetInput { /** The practitioner picked from the staff picker or the name search, if any. */ selectedPractitioner?: Practitioner; /** The selected practitioner's roles, narrowed to the current organization. */ selectedPractitionerRoles?: PractitionerRole[]; /** True when this reader's schedules scope is `own` - they may manage theirs and nobody else's. */ onlyOwnSchedules: boolean; /** The signed-in principal's own Practitioner, when they are one at all. */ ownPractitioner?: Practitioner; /** The signed-in principal's own roles, narrowed to the current organization. */ ownRoles?: PractitionerRole[]; } /** * AN EXPLICIT SELECTION ALWAYS WINS. The own-scope fallback is reached only when nobody has been * chosen, so a reader who CAN pick colleagues behaves exactly as they did before. * * AND THE FALLBACK CAN ONLY EVER RESOLVE TO THE READER. It is fed from the signed-in principal, never * from the staff directory - which is both why it survives the directory being withheld and why it cannot * reach a colleague. A staff member scoped to `own` who is not a Practitioner at all (an HR profile, say) * has no schedule to manage and correctly gets nothing back. */ export const resolveScheduleManageTarget = ( input: ScheduleManageTargetInput, ): ScheduleManageTarget | undefined => { const { selectedPractitioner, selectedPractitionerRoles, onlyOwnSchedules, ownPractitioner, ownRoles } = input; /** * At `own` scope a selection cannot name somebody else, whatever put it there - the page no longer * offers a control that could, but a deep link or a restored filter still can. The server refuses * such a write anyway; a refusal at the end of a filled-in form is a worse screen than an action that * was never offered. * * Falls through to the reader rather than returning nothing: at this scope there is still exactly one * schedule they may manage, and refusing outright would take away their own. */ const selectionIsSomebodyElse = Boolean( onlyOwnSchedules && selectedPractitioner && selectedPractitioner.id !== ownPractitioner?.id, ); if (selectedPractitioner && !selectionIsSomebodyElse) { return { practitioner: selectedPractitioner, roles: selectedPractitionerRoles ?? [], isOwn: onlyOwnSchedules, }; } if (onlyOwnSchedules && ownPractitioner) { return { practitioner: ownPractitioner, roles: ownRoles ?? [], isOwn: true, }; } return undefined; };