283 lines
8.7 KiB
TypeScript
283 lines
8.7 KiB
TypeScript
/** 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-outline",
|
||
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 l’arbre. */
|
||
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"
|
||
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 }
|
||
return normalizeLabelRow({ ...d, ...p, id: d.id })
|
||
})
|
||
|
||
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]
|
||
}
|