import { DateTime } from 'luxon' // Visitor timezone detection (browser); falls back to UTC on the server / when // unavailable. All slot times are transmitted as UTC and rendered in this zone. export function detectTimezone(): string { try { return Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC' } catch { return 'UTC' } } // UTC [from, to) covering one local calendar day in `tz`. export function dayWindowUtc(isoDate: string, tz: string): { from: string; to: string } { const start = DateTime.fromISO(isoDate, { zone: tz }).startOf('day') return { from: start.toUTC().toISO()!, to: start.plus({ days: 1 }).toUTC().toISO()! } } export interface DayOption { iso: string // yyyy-MM-dd in tz weekday: string day: string month: string } // The next `count` calendar days starting today, in the visitor's tz. export function nextDays(tz: string, count: number): DayOption[] { const today = DateTime.now().setZone(tz).startOf('day') return Array.from({ length: count }, (_, i) => { const d = today.plus({ days: i }) return { iso: d.toFormat('yyyy-MM-dd'), weekday: d.toFormat('ccc'), day: d.toFormat('d'), month: d.toFormat('LLL') } }) } export function fmtTime(utc: string, tz: string): string { return DateTime.fromISO(utc).setZone(tz).toFormat('HH:mm') } export function fmtDateLong(utc: string, tz: string): string { return DateTime.fromISO(utc).setZone(tz).toFormat('cccc d LLLL yyyy') } export function fmtRange(startUtc: string, endUtc: string, tz: string): string { const s = DateTime.fromISO(startUtc).setZone(tz) const e = DateTime.fromISO(endUtc).setZone(tz) return `${s.toFormat('cccc d LLLL')} · ${s.toFormat('HH:mm')}–${e.toFormat('HH:mm')} (${tz})` } // Google Calendar "add to calendar" template link (UTC basic format). export function googleCalUrl(p: { title: string; startUtc: string; endUtc: string; details?: string; location?: string }): string { const fmt = (iso: string) => DateTime.fromISO(iso).toUTC().toFormat("yyyyLLdd'T'HHmmss'Z'") const params = new URLSearchParams({ action: 'TEMPLATE', text: p.title, dates: `${fmt(p.startUtc)}/${fmt(p.endUtc)}`, }) if (p.details) params.set('details', p.details) if (p.location) params.set('location', p.location) return `https://calendar.google.com/calendar/render?${params.toString()}` } // Common IANA zones for the manual switcher (visitor tz is added if missing). export const COMMON_TIMEZONES = [ 'Europe/Copenhagen', 'Europe/London', 'Europe/Berlin', 'Europe/Paris', 'Europe/Madrid', 'Europe/Stockholm', 'Europe/Helsinki', 'America/New_York', 'America/Chicago', 'America/Los_Angeles', 'Asia/Dubai', 'Asia/Kolkata', 'Asia/Singapore', 'Asia/Tokyo', 'Australia/Sydney', 'UTC', ]