// / finding B51 - the contact Type list is ordered for the person choosing, not for the server. // // What the front desk saw on `#/dashboard/staff/new`: // "" - Fax - SMS - URL - Email - Other - Pager - Phone // - a blank row first (that half is fixed in `FhirCode`, since no call site should have to know about // it), "Other" stranded in the middle, and the two choices actually picked buried at either end. // // WHY THIS IS ITS OWN MODULE rather than living in `FhirCode`: which codes are common is DOMAIN // knowledge about contact points, and `FhirCode` serves **152 call sites** with no business knowing it. // The generic half - no blank row, a real placeholder - belongs there; the opinion belongs here. // // And why it is a module rather than a const inside the component: it is pure, and a test importing it // through `FhirContactPoint` drags in the services barrel and `environment.ts`, which reads `window`. A // pure function should not need a DOM to be tested. import type { IValueSet } from '../services/ValueSetService'; /** Common first, Other last. Anything unlisted keeps its incoming order, just before `other`. */ export const CONTACT_TYPE_ORDER = ['phone', 'email', 'sms', 'fax', 'pager', 'url', 'other']; export const CONTACT_USE_ORDER = ['mobile', 'home', 'work', 'temp', 'old']; /** * Sorts a ValueSet into the order a human would scan, without dropping anything. * * AN UNLISTED CODE MUST STILL APPEAR, and must not lead the list. The naive lookup (`indexOf`, use it * raw) returns `-1` for anything new, which sorts it to the FRONT - so the day the server adds a contact * channel, it would jump ahead of Phone. Filtering to known codes is worse still: the option silently * disappears and the field cannot express a real value. Unranked codes therefore sort just before the * explicitly-last entry. */ export const orderForHumans = (values: IValueSet[], preferred: string[]): IValueSet[] => { // Half a step BEFORE the last preferred entry, so an unranked code lands after everything explicitly // ranked above it and still ahead of the catch-all ("other", "old"). // Written as `lastIndex - 0.5` rather than `preferred.length - 0.5`, which is the off-by-one this // had first: `length` is one PAST the last index, so that put unranked codes AFTER "other" - the // opposite of the intent, and exactly what the "does not jump to the front" test caught. const unrankedPosition = preferred.length - 1 - 0.5; const rank = (code: string) => { const index = preferred.indexOf(code); return index === -1 ? unrankedPosition : index; }; // Copied before sorting: `Array.prototype.sort` mutates, and these arrays come from a service cache. return [...values].sort((a, b) => rank(a.code) - rank(b.code)); };