/** * WHAT THE ADMINISTRATOR IS TOLD WHEN THE PROVIDER WAS NOT. * * Changing somebody's working hours sends them a notice. The server already decided whether that notice * went anywhere and says so in the `X-Schedule-Notice` response header - but until now nothing read it, * so the save reported a plain success and TWO people ended the interaction with a false belief: the * administrator believed the provider had been told their week moved, and the provider was never going * to learn it. The first anybody finds out is when somebody does not turn up, and by then nothing * connects the two events. * * THE ADMINISTRATOR IS EXACTLY THE PERSON WHO COULD FIX IT. They are already on a staff screen, they can * add the address or pick up the phone, and it costs them one sentence to know. */ /** The outcomes the server distinguishes. Mirrors `ScheduleNoticeOutcome` in the api. */ export type ScheduleNoticeOutcome = | 'sent' | 'skipped-nothing-changed' | 'skipped-own-edit' | 'skipped-no-owner' | 'skipped-no-address' | 'failed'; /** * The sentence to show, or `undefined` for the cases worth saying nothing about. * * SILENCE IS THE COMMON CASE AND IT IS DELIBERATE. A caveat on every save is a caveat nobody reads, so * the three ordinary outcomes - it was sent, nothing actually changed, you edited your own hours - get * no sentence at all. Only a save where somebody SHOULD have been told and was not says anything. * * AND THE TWO FAILURES STAY APART, because they call for opposite actions. A send that threw is probably * transient and is worth trying again; a provider with no address will still have no address tomorrow * and is worth walking down the corridor about. Collapsing them into one "could not notify" tells the * administrator to do the wrong thing half the time. */ export const scheduleNoticeSentence = (outcome: string | null): string | undefined => { switch (outcome) { case 'skipped-no-address': return 'Hours saved. This provider has no contact email, so we could not notify them. Add one on Contact, or tell them yourself.'; case 'skipped-no-owner': return 'Hours saved. No provider is linked to this schedule, so nobody was notified.'; case 'failed': return 'Hours saved, but we could not notify this provider. Try again shortly, or tell them yourself.'; default: // 'sent', 'skipped-nothing-changed', 'skipped-own-edit' - and anything a NEWER server sends // that this build does not recognise. An unknown outcome says nothing rather than inventing // a warning about a state it cannot describe. return undefined; } }; /** * `null` MEANS THE HEADER WAS NOT READABLE, AND THAT IS NOT THE SAME AS A PROBLEM. * * A browser lets script read only the safelisted response headers, so a missing * `Access-Control-Expose-Headers` entry makes `headers.get()` return null while the header is sitting * right there in the network panel - nothing throws and nothing is logged. An older server that does not * send it at all reads identically. * * Either way the honest answer is to say nothing, because we do not know whether anybody was told. * Guessing "not notified" from an unreadable header would put a warning on every save against an older * deployment. */ export const scheduleNoticeIsSilent = (outcome: string | null): boolean => scheduleNoticeSentence(outcome) === undefined;