/** * @file dateRange — the Analytics date range: the preset ids kept in `?range=` * (today / this week from Monday / this month from the 1st / 7d / 30d / 90d / * all / custom), and `rangeDates`, which turns a preset (or * a custom from/to) into the local `YYYY-MM-DD` bounds sent as `from`/`to`. * @author Nguyễn Ngọc Trí Vĩ */ export const RANGE_PRESETS = [ "today", "week", "month", "7d", "30d", "90d", "all", "custom", ] as const; export type RangePreset = (typeof RANGE_PRESETS)[number]; /** Local, inclusive bounds; an absent end is open. */ export interface DateRange { from?: string; to?: string; } /** A `?range=` value, or `all` for anything else. */ export function parsePreset(v: string | null): RangePreset { return (RANGE_PRESETS as readonly string[]).includes(v ?? "") ? (v as RangePreset) : "all"; } /** `d` as a local `YYYY-MM-DD`. */ export function localDate(d: Date): string { const p = (n: number) => String(n).padStart(2, "0"); return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`; } /** The bounds of a preset: `7d` = today and the 6 days before it; `week` * starts on Monday, `month` on the 1st, both ending today. */ export function rangeDates( preset: RangePreset, custom: DateRange = {}, today: Date = new Date() ): DateRange { if (preset === "all") return {}; if (preset === "custom") { return { from: custom.from || undefined, to: custom.to || undefined }; } const start = new Date(today); if (preset === "week") start.setDate(today.getDate() - ((today.getDay() + 6) % 7)); else if (preset === "month") start.setDate(1); else if (preset !== "today") start.setDate(today.getDate() - (parseInt(preset, 10) - 1)); return { from: localDate(start), to: localDate(today) }; } /** Set `from`/`to` (and `tz_offset`, which reads them) on a query string. */ export function applyRange(qs: URLSearchParams, range?: DateRange): URLSearchParams { if (range?.from) qs.set("from", range.from); if (range?.to) qs.set("to", range.to); if ((range?.from || range?.to) && !qs.has("tz_offset")) { qs.set("tz_offset", String(new Date().getTimezoneOffset())); } return qs; }