Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Refactored metadata for contacts, administration, and Ulticards pages to utilize dynamic app names and descriptions. - Introduced new product pages for Ultiai, Ultical, Ulticards, Ultidrive, Ultimail, and Ultimeet with appropriate metadata. - Enhanced layout components to ensure consistent styling and functionality across new product sections. - Updated various components to replace hardcoded labels with dynamic references to improve maintainability and consistency.
133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
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)
|
||
}
|
||
}
|