ultisuite-client/lib/sidebar-nav-data.ts

288 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** Données navigation dossiers / libellés (partagées sidebar + filtre mails). */
import {
buildEmailLabelToSidebarFolderId,
buildFolderIdToLabelRecord,
type FolderTreeNode,
type LabelRowItem,
} from "@/lib/sidebar-nav-maps"
export type { FolderTreeNode, LabelRowItem } from "@/lib/sidebar-nav-maps"
export const folderTree: FolderTreeNode[] = [
{
id: "folder-travail",
label: "Travail",
color: "bg-blue-500",
count: 24,
children: [
{ id: "folder-travail-clients", label: "Clients", color: "bg-blue-400", count: 11 },
{
id: "folder-travail-projets",
label: "Projets",
color: "bg-blue-400",
count: 8,
children: [
{ id: "folder-travail-projets-q1", label: "Q1 2026", color: "bg-sky-400", count: 3 },
{ id: "folder-travail-projets-archive", label: "Archives projets", color: "bg-slate-400", count: 5 },
],
},
{ id: "folder-travail-rh", label: "RH", color: "bg-blue-400", count: 5 },
],
},
{
id: "folder-perso",
label: "Personnel",
color: "bg-emerald-500",
count: 18,
children: [
{ id: "folder-perso-voyages", label: "Voyages", color: "bg-emerald-400", count: 6 },
{ id: "folder-perso-famille", label: "Famille", color: "bg-emerald-400", count: 12 },
],
},
{ id: "folder-factures", label: "Factures", color: "bg-amber-500", count: 42 },
]
export function normalizeLabelRow(row: LabelRowItem): LabelRowItem {
return {
...row,
tabbed: row.tabbed ?? false,
favorite: row.favorite ?? false,
excludeFromPrincipal: row.excludeFromPrincipal ?? false,
showInMessageList: row.showInMessageList ?? true,
enabled: row.enabled ?? true,
}
}
/** Libellés navigation système (onglets + catégories) — ids stables proches du titre. */
export const SYSTEM_NAV_LABEL_DEFAULTS: readonly LabelRowItem[] = [
{
id: "promotions",
label: "Promotions",
color: "bg-[#1e8e3e]",
icon: "mdi:tag",
tabbed: true,
favorite: true,
excludeFromPrincipal: true,
showInMessageList: false,
enabled: true,
},
{
id: "reseaux-sociaux",
label: "Réseaux sociaux",
color: "bg-[#0b57d0]",
icon: "mdi:account-group",
tabbed: true,
favorite: true,
excludeFromPrincipal: true,
showInMessageList: false,
enabled: true,
},
{
id: "newsletters",
label: "Newsletters",
color: "bg-[#e8710a]",
icon: "mdi:email-newsletter",
tabbed: true,
favorite: true,
excludeFromPrincipal: true,
showInMessageList: false,
enabled: true,
},
{
id: "mises-a-jour",
label: "Mises à jour",
color: "bg-[#c5221f]",
icon: "mdi:update",
tabbed: true,
favorite: true,
excludeFromPrincipal: true,
showInMessageList: false,
enabled: true,
},
{
id: "forums",
label: "Forums",
color: "bg-[#9334e6]",
icon: "mdi:forum",
tabbed: true,
favorite: true,
excludeFromPrincipal: true,
showInMessageList: false,
enabled: true,
},
{
id: "achats",
label: "Achats",
color: "bg-amber-600",
icon: "mdi:cart-outline",
tabbed: false,
favorite: false,
excludeFromPrincipal: false,
showInMessageList: true,
enabled: true,
},
{
id: "deplacements",
label: "Déplacements",
color: "bg-teal-600",
icon: "mdi:map-marker",
tabbed: false,
favorite: false,
excludeFromPrincipal: false,
showInMessageList: true,
enabled: true,
},
{
id: "finance",
label: "Finance",
color: "bg-indigo-600",
icon: "mdi:credit-card-outline",
tabbed: false,
favorite: false,
excludeFromPrincipal: false,
showInMessageList: true,
enabled: true,
},
] as const
export const SYSTEM_NAV_LABEL_ID_SET = new Set(SYSTEM_NAV_LABEL_DEFAULTS.map((r) => r.id))
const DEMO_IMAP_LABEL_ROWS: readonly LabelRowItem[] = [
{ id: "imap-sent", label: "[Imap]/Sent", color: "bg-gray-500" },
{ id: "imap-trash", label: "[Imap]/Trash", color: "bg-red-400", count: 4 },
{ id: "browser-alerts", label: "BrowserAlerts", color: "bg-red-400", count: 1 },
{ id: "cctv", label: "CCTV", color: "bg-red-400" },
{ id: "cm-security", label: "CMSecurity Alerts", color: "bg-red-400", count: 14 },
{ id: "twitch", label: "Twitch", color: "bg-purple-500", count: 137 },
]
/** Tous les libellés par défaut (système + démo IMAP) — ordre stable. */
export const DEFAULT_NAV_LABEL_ROWS: LabelRowItem[] = [
...SYSTEM_NAV_LABEL_DEFAULTS.map((r) => normalizeLabelRow({ ...r })),
...DEMO_IMAP_LABEL_ROWS.map((r) => normalizeLabelRow({ ...r })),
]
/** Snapshot pour filtres quand aucun contexte nav (tests, défaut). */
export const defaultNavLabelRowsSnapshot: LabelRowItem[] = DEFAULT_NAV_LABEL_ROWS.map((r) => ({ ...r }))
export function isSystemNavLabelId(id: string): boolean {
return SYSTEM_NAV_LABEL_ID_SET.has(id)
}
/** Libellés visibles en onglets boîte de réception (hors Principale). */
export function tabbedInboxLabelRows(rows: readonly LabelRowItem[]): LabelRowItem[] {
return rows.filter((r) => r.enabled !== false && r.tabbed === true)
}
export function favoriteNavLabelRows(rows: readonly LabelRowItem[]): LabelRowItem[] {
return rows.filter((r) => r.enabled !== false && r.favorite === true)
}
export function nonTabbedNavLabelRows(rows: readonly LabelRowItem[]): LabelRowItem[] {
return rows.filter((r) => r.enabled !== false && r.tabbed !== true && SYSTEM_NAV_LABEL_ID_SET.has(r.id))
}
export function labelRowById(
rows: readonly LabelRowItem[],
id: string
): LabelRowItem | undefined {
return rows.find((r) => r.id === id)
}
/** id de ligne sidebar (dossier hiérarchique ou libellé) → libellé pour matcher `email.labels`. */
export const sidebarNavFolderIdToLabel: Readonly<Record<string, string>> =
buildFolderIdToLabelRecord(folderTree, defaultNavLabelRowsSnapshot)
/** Libellé Gmail (comme dans `email.labels`) → id de ligne sidebar correspondant. */
export const emailLabelToSidebarFolderId: Readonly<Record<string, string>> =
buildEmailLabelToSidebarFolderId(sidebarNavFolderIdToLabel)
/** Libellés navigation dossiers système — hors libellés définis dans `labelRows`. */
const STATIC_NAV_FOLDER_LABELS: Record<string, string> = {
inbox: "Boîte de réception",
starred: "Messages suivis",
snoozed: "En attente",
important: "Important",
sent: "Messages envoyés",
drafts: "Brouillons",
scheduled: "Planifié",
spam: "Indésirables",
trash: "Corbeille",
}
/** Libellé lisible pour id de ligne (liste vide, messages détat). Dossiers / libellés IMAP viennent de larbre. */
export function getMailNavFolderLabel(
folderId: string,
dynamicFolderIdToLabel?: Record<string, string>
): string {
const fromStatic = STATIC_NAV_FOLDER_LABELS[folderId]
if (fromStatic) return fromStatic
const mapped =
dynamicFolderIdToLabel?.[folderId] ?? sidebarNavFolderIdToLabel[folderId]
if (mapped && mapped !== "scheduled") return mapped
return folderId
}
export function inboxTabDisplayLabel(
inboxTab: string,
labelRows: readonly LabelRowItem[],
folderIdToLabel: Record<string, string>
): string {
if (inboxTab === "primary") return "Principale"
if (inboxTab === "all") return "Tous les messages"
const row = labelRowById(labelRows, inboxTab)
if (row && row.enabled !== false) return row.label
return getMailNavFolderLabel(inboxTab, folderIdToLabel)
}
export function cloneDefaultFolderTree(): FolderTreeNode[] {
return structuredClone(folderTree)
}
export function cloneDefaultLabelRows(): LabelRowItem[] {
return DEFAULT_NAV_LABEL_ROWS.map((r) => ({ ...r }))
}
const LEGACY_LABEL_ROW_ID_MAP: Record<string, string> = {
purchases: "achats",
travel: "deplacements",
social: "reseaux-sociaux",
updates: "mises-a-jour",
notifications: "newsletters",
}
/** Fusionne la persistance avec les défauts (ids système + nouveaux champs). */
export function reconcileLabelRowsFromPersisted(persisted: LabelRowItem[] | undefined): LabelRowItem[] {
const defaults = cloneDefaultLabelRows()
const defaultIds = new Set(defaults.map((r) => r.id))
const persistByResolvedId = new Map<string, LabelRowItem>()
for (const p of persisted ?? []) {
const resolvedId = LEGACY_LABEL_ROW_ID_MAP[p.id] ?? p.id
persistByResolvedId.set(resolvedId, { ...p, id: resolvedId })
}
const merged = defaults.map((d) => {
const p = persistByResolvedId.get(d.id)
if (!p) return { ...d }
const row = normalizeLabelRow({ ...d, ...p, id: d.id })
if (SYSTEM_NAV_LABEL_ID_SET.has(d.id)) {
return { ...row, icon: d.icon, color: d.color }
}
return row
})
const mergedIds = new Set(merged.map((r) => r.id))
const extras: LabelRowItem[] = []
for (const p of persisted ?? []) {
const resolvedId = LEGACY_LABEL_ROW_ID_MAP[p.id] ?? p.id
if (!mergedIds.has(resolvedId)) {
extras.push(normalizeLabelRow({ ...p, id: resolvedId }))
mergedIds.add(resolvedId)
}
}
return [...merged, ...extras]
}