import dayjs, { type Dayjs } from "dayjs" import localizedFormat from "dayjs/plugin/localizedFormat" import relativeTime from "dayjs/plugin/relativeTime" import "dayjs/locale/fr" import "dayjs/locale/en" dayjs.extend(localizedFormat) dayjs.extend(relativeTime) const SUPPORTED_LOCALES = new Set(["fr", "en", "de", "es", "it", "pt", "nl", "pl", "ja", "zh"]) let activeLocale: string | null = null /** Browser locale for dayjs (client); stable fallback on server. */ export function resolveMailDateLocale(): string { if (typeof navigator === "undefined") return "fr" const base = navigator.language.split("-")[0]?.toLowerCase() ?? "fr" return SUPPORTED_LOCALES.has(base) ? base : "en" } export function ensureMailDateLocale(): void { const next = resolveMailDateLocale() if (activeLocale === next) return dayjs.locale(next) activeLocale = next } export function parseMailDate(iso: string): Dayjs | null { if (!iso?.trim()) return null const d = dayjs(iso) return d.isValid() ? d : null } export type MailDateDisplayVariant = "list" | "preview" | "previewShort" | "detail" const TWO_WEEKS_MS = 14 * 24 * 60 * 60 * 1000 function formatMailPreviewRelative(d: Dayjs, now: Dayjs): string | null { if (d.isAfter(now)) return null const msAgo = now.valueOf() - d.valueOf() const withinTwoWeeks = msAgo >= 0 && msAgo < TWO_WEEKS_MS if (d.isSame(now, "day") || withinTwoWeeks) { return `(${d.fromNow()})` } return null } function relativeSuffix(d: Dayjs, now: Dayjs): string { const relative = formatMailPreviewRelative(d, now) return relative ? ` ${relative}` : "" } /** Colonne date de la liste (fuseau navigateur). */ export function formatMailListDate(iso: string, now: Dayjs = dayjs()): string { ensureMailDateLocale() const d = parseMailDate(iso) if (!d) return "—" if (d.isSame(now, "day")) { return d.format("LT") } if (d.isSame(now, "year")) { return d.format("D MMM") } return d.format("L") } /** Date seule pour l’en-tête / aperçu (sans relatif). */ export function formatMailPreviewDatePrimary(iso: string, now: Dayjs = dayjs()): string { ensureMailDateLocale() const d = parseMailDate(iso) if (!d) return "—" const time = d.format("LT") if (d.isSame(now, "day")) { return time } const datePart = d.format("ddd D MMM") if (d.isSame(now, "year")) { return `${datePart} ${time}` } return `${d.format("ddd D MMM YYYY")} ${time}` } /** Relatif « (il y a …) » pour l’aperçu, ou null si absent. */ export function formatMailPreviewDateRelative( iso: string, now: Dayjs = dayjs() ): string | null { ensureMailDateLocale() const d = parseMailDate(iso) if (!d) return null return formatMailPreviewRelative(d, now) } /** En-tête / aperçu d’un message (fuseau navigateur). */ export function formatMailPreviewDate(iso: string, now: Dayjs = dayjs()): string { ensureMailDateLocale() const d = parseMailDate(iso) if (!d) return "—" return `${formatMailPreviewDatePrimary(iso, now)}${relativeSuffix(d, now)}` } /** Citations, impression, panneau « détails » (sans relatif). */ export function formatMailDetailDate(iso: string, now: Dayjs = dayjs()): string { ensureMailDateLocale() const d = parseMailDate(iso) if (!d) return "—" const time = d.format("LT") const datePart = d.format("ddd D MMM") if (d.isSame(now, "year")) { return `${datePart} ${time}` } return `${d.format("ddd D MMM YYYY")} ${time}` } export function formatMailDate(iso: string, variant: MailDateDisplayVariant): string { switch (variant) { case "list": case "previewShort": return formatMailListDate(iso) case "preview": return formatMailPreviewDate(iso) case "detail": return formatMailDetailDate(iso) } }