/** Date filtering for the oil/diesel "Booked out" table. Days are South African calendar days. */ export type LogPreset = "today" | "week" | "month" | "all" | "range"; const dayFmt = new Intl.DateTimeFormat("en-CA", { timeZone: "Africa/Johannesburg" }); /** "2026-10-22" for an instant, in SA time. PocketBase stamps look like "2026-10-22 08:15:00.000Z". */ export function saDay(stamp: string): string { if (!stamp || Number.isNaN(new Date(stamp.replace(" ", "T")).getTime())) return ""; return dayFmt.format(new Date(stamp.replace(" ", "T"))); } function addDays(day: string, n: number): string { const d = new Date(`${day}T00:00:00Z`); d.setUTCDate(d.getUTCDate() + n); return d.toISOString().slice(0, 10); } /** Inclusive [from, to] day bounds for a preset; null bound = open. Weeks start Monday. */ export function presetBounds(preset: LogPreset, today: string, from = "", to = ""): [string | null, string | null] { switch (preset) { case "today": return [today, today]; case "week": { const dow = (new Date(`${today}T00:00:00Z`).getUTCDay() + 6) % 7; // Mon=0 return [addDays(today, -dow), today]; } case "month": return [`${today.slice(0, 7)}-01`, today]; case "range": return [from || null, to || null]; default: return [null, null]; } } export function inBounds(day: string, [from, to]: [string | null, string | null]): boolean { if (!day) return !from && !to; // undated rows only show when no period is applied return (!from || day >= from) && (!to || day <= to); } /** * When a movement happened. `created` is NOT reliable on oil_stock_movements (the collection * was made through the API, so the field never auto-fills), so book-outs store a full ISO * instant in `occurred_on`. Older rows hold a bare date. Returns "" when neither is usable. */ export function movementAt(m: { [k: string]: any }): string { for (const v of [m.occurred_on, m.created] as (string | undefined)[]) { if (v && !Number.isNaN(new Date(v.replace(" ", "T")).getTime())) return v; } return ""; }