// Weekly hours as Settings edits them: one span a day, Monday first, or closed. A day stored with // more than one span keeps the others as they are; closing the day clears them all. Pure. import type { WeeklyHours } from "../api/types"; /** View days, Monday first (0 is Sunday). */ export const WEEK = [1, 2, 3, 4, 5, 6, 0] as const; export const DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; type Span = { open: string; close: string }; export type DayRow = { day: number; open: boolean; from: string; to: string; more: Span[] }; export function dayRows(hours: WeeklyHours): DayRow[] { return WEEK.map((day) => { const spans = hours.filter((h) => h.day === day).sort((a, b) => a.open.localeCompare(b.open)); return { day, open: spans.length > 0, from: spans[0]?.open ?? "08:00", to: spans[0]?.close ?? "17:00", more: spans.slice(1).map(({ open, close }) => ({ open, close })) }; }); } export function hoursFrom(rows: DayRow[]): WeeklyHours { return rows.flatMap((r) => (r.open ? [{ day: r.day, open: r.from, close: r.to }, ...r.more.map((m) => ({ day: r.day, ...m }))] : [])); } export const changeDay = (rows: DayRow[], day: number, change: Partial>): DayRow[] => rows.map((r) => (r.day === day ? { ...r, ...change, more: change.open === false ? [] : r.more } : r)); const CLOCK = /^([01]\d|2[0-3]):[0-5]\d$/; /** Each open day's problem in plain words, by day. Empty when the hours can be saved. */ export function hoursErrors(rows: DayRow[]): Record { const errors: Record = {}; for (const r of rows) { if (!r.open) continue; if (!CLOCK.test(r.from) || !CLOCK.test(r.to)) errors[r.day] = `${DAY_NAMES[r.day]}: enter an opening and a closing time, for example 08:00 and 17:00.`; else if (r.from >= r.to) errors[r.day] = `${DAY_NAMES[r.day]}: the closing time must be after the opening time.`; } return errors; } /** Same hours in the same order, so Settings sends them only when they changed. */ export const sameHours = (a: WeeklyHours, b: WeeklyHours) => JSON.stringify(hoursFrom(dayRows(a))) === JSON.stringify(hoursFrom(dayRows(b))); /** Every time zone the browser knows, with the clinic's own first in the list if it is missing. */ export function timeZones(current: string): string[] { const known = typeof Intl.supportedValuesOf === "function" ? Intl.supportedValuesOf("timeZone") : []; return known.includes(current) ? known : [current, ...known]; }