/** * THE TIME ZONES, IN AN ORDER A PERSON CAN SCAN. * * The HL7 time-zone value set arrives ordered by string LENGTH - `UTC`, then every eight-character * identifier, then every nine-character one - which is what sorting identifiers with no comparator * produces. `America/Chicago` sat at option 204 of 420. Alphabetical is not a preference over that; it * is the difference between a list and a pile. * * IT IS A UTIL RATHER THAN A LINE IN A FORM, AND THAT IS THE WHOLE POINT. Three separate screens offer * this field - a location, the organization profile, and the founding setup wizard a practice meets on * about its fourth screen. When the sort lived in one of them the other two kept the pile, including the * wizard. A fourth screen would have made the same mistake for the same reason, so the sort now lives * behind the one function that fetches the value set and no screen has to remember it. * * PRESENTATION ONLY. The stored value is the IANA identifier either way, which is what the server and * every renderer read. Nothing is filtered and nothing is demoted: every zone the value set carries is * still here, so a practice with an overseas location still finds it. */ export interface TimezoneOption { code?: string; display?: string; } /** * Sorted by what the person actually reads, falling back to the code. * * `localeCompare` rather than `<`, because the raw comparison orders by code unit and would put every * uppercase letter before every lowercase one - which is not a defect this value set can show today, * and is one it would show the first time a display string arrived that was not title case. */ export const sortTimezoneOptions = (zones: readonly T[]): T[] => [...zones].sort((a, b) => (a.display ?? a.code ?? '').localeCompare(b.display ?? b.code ?? ''));