import type { DashboardRange } from "@/lib/analytics/dashboardQueries"; export type RangeKey = "today" | "7d" | "30d" | "90d" | "custom"; export const RANGE_OPTIONS: { key: RangeKey; label: string; days: number | "today" }[] = [ { key: "today", label: "Heute", days: "today" }, { key: "7d", label: "7 Tage", days: 7 }, { key: "30d", label: "30 Tage", days: 30 }, { key: "90d", label: "90 Tage", days: 90 }, ]; const DAY_MS = 24 * 60 * 60 * 1000; function startOfUTCDay(date: Date): Date { return new Date(`${date.toISOString().slice(0, 10)}T00:00:00.000Z`); } function endOfUTCDay(date: Date): Date { return new Date(`${date.toISOString().slice(0, 10)}T23:59:59.999Z`); } function parseDateParam(value: string | null): Date | null { if (!value || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return null; const date = new Date(`${value}T00:00:00.000Z`); return Number.isNaN(date.getTime()) ? null : date; } /** * Resolves the dashboard's period filter (?range=&from=&to=) into an actual * date range, clamped to `maxDaysBack` (the configured raw-event retention — * see globals/AnalyticsSettings.ts) so the UI never claims to show data that * has already been purged. Also computes the matching "previous period" for * comparison (same length, immediately preceding). */ export function resolveRange( searchParams: URLSearchParams, maxDaysBack: number, ): { key: RangeKey; range: DashboardRange; compareRange: DashboardRange } { const now = new Date(); const earliestAllowed = startOfUTCDay(new Date(now.getTime() - maxDaysBack * DAY_MS)); const rawKey = searchParams.get("range"); const key: RangeKey = (["today", "7d", "30d", "90d", "custom"] as const).includes(rawKey as RangeKey) ? (rawKey as RangeKey) : "7d"; if (key === "custom") { const fromParam = parseDateParam(searchParams.get("from")); const toParam = parseDateParam(searchParams.get("to")); let from = fromParam ? startOfUTCDay(fromParam) : startOfUTCDay(new Date(now.getTime() - 7 * DAY_MS)); let to = toParam ? endOfUTCDay(toParam) : now; if (from < earliestAllowed) from = earliestAllowed; if (to > now) to = now; if (from > to) from = to; const lengthMs = to.getTime() - from.getTime(); const compareRange: DashboardRange = { from: new Date(from.getTime() - lengthMs), to: new Date(from.getTime() - 1) }; return { key, range: { from, to }, compareRange }; } if (key === "today") { const from = startOfUTCDay(now); const yesterday = new Date(from.getTime() - DAY_MS); return { key, range: { from, to: now }, compareRange: { from: yesterday, to: new Date(from.getTime() - 1) } }; } const days = RANGE_OPTIONS.find((o) => o.key === key)?.days; const windowDays = typeof days === "number" ? Math.min(days, maxDaysBack) : 7; const from = new Date(Math.max(now.getTime() - windowDays * DAY_MS, earliestAllowed.getTime())); const compareRange: DashboardRange = { from: new Date(from.getTime() - windowDays * DAY_MS), to: new Date(from.getTime() - 1) }; return { key, range: { from, to: now }, compareRange }; }