"use client" import { useMemo } from "react" import { useLabels } from "@/lib/api/hooks/use-folder-label-queries" import { useUnifiedFolders } from "@/lib/api/hooks/use-unified-folder-queries" import { useImapFolders } from "@/lib/api/hooks/use-imap-folders" import { useMailAccounts } from "@/lib/api/hooks/use-mail-queries" import { useContactsList } from "@/lib/contacts/use-contacts-list" import { fullContactDisplayName } from "@/lib/contacts/types" import type { AgendaInvitationExclusion } from "@/lib/agenda/agenda-settings-types" import { exclusionKey } from "@/lib/agenda/agenda-settings-types" import { buildDestinationMailboxes, destinationEmailFromStoredKey, } from "@/lib/agenda/agenda-destination-identities" import { identityKey } from "@/lib/agenda/agenda-store" import { useComposeIdentitiesStore } from "@/lib/stores/compose-identities-store" export type AgendaImportSuggestion = AgendaInvitationExclusion & { id: string group: string } const MAILBOX_SUGGESTIONS: AgendaInvitationExclusion[] = [ { type: "mailbox", value: "spam", label: "Spam" }, { type: "mailbox", value: "trash", label: "Corbeille" }, { type: "mailbox", value: "promotions", label: "Promotions" }, { type: "mailbox", value: "social", label: "Réseaux sociaux" }, { type: "mailbox", value: "updates", label: "Notifications" }, ] function matchesQuery(text: string, query: string): boolean { return text.toLowerCase().includes(query.toLowerCase()) } export function useAgendaDestinationMailboxes() { const identities = useComposeIdentitiesStore((s) => s.identities) const { data: accounts = [] } = useMailAccounts() return useMemo( () => buildDestinationMailboxes(identities, accounts.map((a) => a.email)), [identities, accounts], ) } export function useAgendaInvitationSuggestions( query: string, taken: Set, opts?: { types?: AgendaInvitationExclusion["type"][] }, ) { const { contacts } = useContactsList() const identities = useComposeIdentitiesStore((s) => s.identities) const { data: accounts = [] } = useMailAccounts() const destinationMailboxes = useMemo( () => buildDestinationMailboxes(identities, accounts.map((a) => a.email)), [identities, accounts], ) const { data: labels = [] } = useLabels() const { data: unifiedFolders = [] } = useUnifiedFolders("all") const { folders: imapFolders = [] } = useImapFolders() return useMemo(() => { const q = query.trim() const allowed = opts?.types const includeType = (type: AgendaInvitationExclusion["type"]) => !allowed || allowed.includes(type) const out: AgendaImportSuggestion[] = [] const seenSuggestionIds = new Set() const push = (suggestion: AgendaImportSuggestion) => { if (seenSuggestionIds.has(suggestion.id)) return seenSuggestionIds.add(suggestion.id) out.push(suggestion) } if (includeType("not_in_contacts")) { const allRule: AgendaInvitationExclusion = { type: "not_in_contacts", value: "", label: "Toute personne pas dans les contacts", } const allId = exclusionKey(allRule) if (!taken.has(allId) && (!q || matchesQuery(allRule.label, q))) { push({ ...allRule, id: allId, group: "Règles contacts" }) } const seenIdentityKeys = new Set() for (const identity of identities) { const key = identityKey(identity.email, identity.accountId) if (seenIdentityKeys.has(key)) continue seenIdentityKeys.add(key) const rule: AgendaInvitationExclusion = { type: "not_in_contacts", value: key, label: `Personnes pas dans les contacts de ${identity.name || identity.email}`, } const id = exclusionKey(rule) if (taken.has(id)) continue if (q && !matchesQuery(rule.label, q) && !matchesQuery(identity.email, q)) continue push({ ...rule, id, group: "Règles contacts" }) } } if (includeType("identity")) { for (const mailbox of destinationMailboxes) { const rule: AgendaInvitationExclusion = { type: "identity", value: mailbox.key, label: mailbox.label, } const id = exclusionKey(rule) if (taken.has(id)) continue if (q && !matchesQuery(mailbox.label, q) && !matchesQuery(mailbox.key, q)) continue push({ ...rule, id, group: "Mails de destination" }) } } if (includeType("contact")) { for (const contact of contacts) { const name = fullContactDisplayName(contact) for (const { value: email } of contact.emails) { if (!email) continue const rule: AgendaInvitationExclusion = { type: "contact", value: email, label: name ? `${name} <${email}>` : email, } const id = exclusionKey(rule) if (taken.has(id)) continue if (q && !matchesQuery(rule.label, q) && !matchesQuery(email, q)) continue push({ ...rule, id, group: "Contacts" }) if (out.length > 40) break } } } if (includeType("email") && q.includes("@")) { const rule: AgendaInvitationExclusion = { type: "email", value: q, label: q, } const id = exclusionKey(rule) if (!taken.has(id)) push({ ...rule, id, group: "Adresses" }) } if (includeType("label")) { for (const label of labels) { const rule: AgendaInvitationExclusion = { type: "label", value: label.name, label: `Libellé · ${label.name}`, } const id = exclusionKey(rule) if (taken.has(id)) continue if (q && !matchesQuery(label.name, q)) continue push({ ...rule, id, group: "Libellés" }) } } if (includeType("folder")) { const folders = [ ...unifiedFolders.map((f) => ({ value: f.id, label: `Dossier · ${f.name}`, })), ...imapFolders.map((f) => ({ value: f.name, label: `Dossier · ${f.name}`, })), ] for (const folder of folders) { const rule: AgendaInvitationExclusion = { type: "folder", value: folder.value, label: folder.label, } const id = exclusionKey(rule) if (taken.has(id)) continue if (q && !matchesQuery(folder.label, q)) continue push({ ...rule, id, group: "Dossiers" }) } } if (includeType("mailbox")) { for (const mailbox of MAILBOX_SUGGESTIONS) { const id = exclusionKey(mailbox) if (taken.has(id)) continue if (q && !matchesQuery(mailbox.label, q)) continue push({ ...mailbox, id, group: "Boîtes mail" }) } } return out.slice(0, 12) }, [ contacts, identities, destinationMailboxes, labels, unifiedFolders, imapFolders, query, taken, opts?.types, ]) } export function identityLabelFromKey(key: string): string { const identities = useComposeIdentitiesStore.getState().identities const found = identities.find((i) => identityKey(i.email, i.accountId) === key) if (!found) return key return `${found.name} <${found.email}>` } export function useAgendaSettingsIdentityOptions() { const identities = useComposeIdentitiesStore((s) => s.identities) return useMemo(() => { const seen = new Set() const out: { key: string; label: string }[] = [] for (const identity of identities) { const key = identityKey(identity.email, identity.accountId) if (seen.has(key)) continue seen.add(key) out.push({ key, label: `${identity.name} <${identity.email}>`, }) } return out }, [identities]) } export function useAgendaSettingsDestinationOptions() { return useAgendaDestinationMailboxes() } /** Libellé d'une clé stockée (legacy identité ou email de destination). */ export function destinationLabelFromStoredKey( key: string, mailboxes: ReturnType, ): string { return ( mailboxes.find((m) => m.key === destinationEmailFromStoredKey(key))?.label ?? destinationEmailFromStoredKey(key) ) }