import type { Email } from "@/lib/email-data" import { folderTree as defaultFolderTree, sidebarNavFolderIdToLabel as defaultSidebarNavFolderIdToLabel, type FolderTreeNode, } from "@/lib/sidebar-nav-data" import { collectSubtreeFolderIds } from "@/lib/sidebar-nav-maps" export type MailFolderFilterCtx = { starredEmailIds: string[] importantEmailIds: string[] } /** Carte navigation dynamique (sidebar). Si absent, valeurs par défaut du module. */ export type MailNavFolderMaps = { folderIdToLabel: Record folderTree: FolderTreeNode[] } const CATEGORY_EMAIL_TAB_IDS = new Set([ "social", "promotions", "updates", "forums", ]) /** Catégories latérales (sidebar) → libellé optionnel sur `email.labels`. */ const SIDEBAR_CATEGORY_EXTRA_LABEL: Partial> = { purchases: "Achats", travel: "Déplacements", finance: "Finance", } function effectiveStarred(email: Email, ctx: MailFolderFilterCtx): boolean { return ctx.starredEmailIds.includes(email.id) || email.starred } function effectiveImportant(email: Email, ctx: MailFolderFilterCtx): boolean { return ctx.importantEmailIds.includes(email.id) || email.important } function isInInbox(email: Email): boolean { if (email.spam) return false const ls = email.labels if (!ls?.length) return true return ls.includes("inbox") } function resolveNavMaps(maps?: MailNavFolderMaps | null): MailNavFolderMaps { if (maps) return maps return { folderIdToLabel: defaultSidebarNavFolderIdToLabel as Record, folderTree: defaultFolderTree, } } function emailHasAnyLabel(email: Email, labels: string[]): boolean { const ls = email.labels if (!ls?.length) return false const lower = new Set(ls.map((x) => x.toLowerCase())) return labels.some((lab) => lower.has(lab.toLowerCase())) } function matchesFolderLabelRow( email: Email, folderId: string, maps: MailNavFolderMaps ): boolean { const label = maps.folderIdToLabel[folderId] if (!label) return false return emailHasAnyLabel(email, [label]) } /** Dossier hiérarchique : ce nœud ou n'importe quel sous-dossier (décompte unique par mail). */ function matchesLabelNav( email: Email, folderId: string, maps: MailNavFolderMaps, subtreeIdsCache?: Map ): boolean { let subtreeIds: string[] | null if (subtreeIdsCache) { if (!subtreeIdsCache.has(folderId)) { subtreeIdsCache.set( folderId, collectSubtreeFolderIds(maps.folderTree, folderId) ) } subtreeIds = subtreeIdsCache.get(folderId) ?? null } else { subtreeIds = collectSubtreeFolderIds(maps.folderTree, folderId) } if (subtreeIds) { return subtreeIds.some((id) => matchesFolderLabelRow(email, id, maps)) } return matchesFolderLabelRow(email, folderId, maps) } export function emailMatchesFolder( email: Email, folderId: string, ctx: MailFolderFilterCtx, maps?: MailNavFolderMaps | null, /** Réutiliser entre appels (ex. `computeFolderUnreadCounts`) pour éviter de rescanner l’arbre à chaque mail. */ subtreeIdsCache?: Map ): boolean { const nav = resolveNavMaps(maps) switch (folderId) { case "inbox": return isInInbox(email) case "starred": return effectiveStarred(email, ctx) case "snoozed": return email.labels?.includes("snoozed") ?? false case "important": return effectiveImportant(email, ctx) case "sent": return email.labels?.includes("sent") ?? false case "drafts": return email.labels?.includes("drafts") ?? false case "scheduled": return email.labels?.includes("scheduled") ?? false case "spam": return email.spam === true || (email.labels?.includes("spam") ?? false) case "notifications": return email.category === "updates" case "purchases": case "travel": case "finance": { const extra = SIDEBAR_CATEGORY_EXTRA_LABEL[folderId] if (!extra) return false return email.labels?.includes(extra) ?? false } default: break } if (CATEGORY_EMAIL_TAB_IDS.has(folderId)) { return email.category === folderId } if (nav.folderIdToLabel[folderId]) { return matchesLabelNav(email, folderId, nav, subtreeIdsCache) } if (email.labels?.includes(folderId)) return true return false }