"use client" import { create } from "zustand" import { persist } from "zustand/middleware" /** * Persistent mail store — survives across navigations and page reloads. * Tracks user-driven mutations on top of the static `emails` array from email-data.ts. * Designed for future server sync: every action is a discrete delta. */ export type LabelEditState = { additions: Record removals: Record } type MailStoreState = { readOverrides: Record starredIds: string[] importantIds: string[] labelEdits: LabelEditState hiddenEmailIds: string[] seenEmailIds: string[] recentMoveTargets: string[] /** Dernières boîtes visitées (clés `mailNavVisitKey`), la plus récente en tête. */ recentFolderVisits: string[] } type MailStoreActions = { setReadOverride: (id: string, read: boolean) => void setReadOverrides: (overrides: Record) => void toggleStar: (id: string) => void setStar: (id: string, starred: boolean) => void toggleImportant: (id: string) => void setImportant: (id: string, important: boolean) => void addLabel: (emailId: string, label: string) => void removeLabel: (emailId: string, label: string) => void setLabelEdits: (updater: (prev: LabelEditState) => LabelEditState) => void hideEmail: (id: string) => void hideEmails: (ids: string[]) => void unhideEmail: (id: string) => void markSeen: (id: string) => void resetHidden: () => void pushRecentMoveTarget: (targetId: string) => void pushRecentFolderVisit: (visitKey: string) => void } export const useMailStore = create()( persist( (set) => ({ readOverrides: {}, starredIds: [], importantIds: [], labelEdits: { additions: {}, removals: {} }, hiddenEmailIds: [], seenEmailIds: [], recentMoveTargets: [], recentFolderVisits: [], setReadOverride: (id, read) => set((s) => ({ readOverrides: { ...s.readOverrides, [id]: read } })), setReadOverrides: (overrides) => set((s) => ({ readOverrides: { ...s.readOverrides, ...overrides } })), toggleStar: (id) => set((s) => ({ starredIds: s.starredIds.includes(id) ? s.starredIds.filter((x) => x !== id) : [...s.starredIds, id], })), setStar: (id, starred) => set((s) => ({ starredIds: starred ? s.starredIds.includes(id) ? s.starredIds : [...s.starredIds, id] : s.starredIds.filter((x) => x !== id), })), toggleImportant: (id) => set((s) => ({ importantIds: s.importantIds.includes(id) ? s.importantIds.filter((x) => x !== id) : [...s.importantIds, id], })), setImportant: (id, important) => set((s) => ({ importantIds: important ? s.importantIds.includes(id) ? s.importantIds : [...s.importantIds, id] : s.importantIds.filter((x) => x !== id), })), addLabel: (emailId, label) => set((s) => { const curr = s.labelEdits.additions[emailId] ?? [] if (curr.some((l) => l.toLowerCase() === label.toLowerCase())) return s return { labelEdits: { additions: { ...s.labelEdits.additions, [emailId]: [...curr, label] }, removals: { ...s.labelEdits.removals, [emailId]: (s.labelEdits.removals[emailId] ?? []).filter( (r) => r.toLowerCase() !== label.toLowerCase() ), }, }, } }), removeLabel: (emailId, label) => set((s) => { const curr = s.labelEdits.removals[emailId] ?? [] if (curr.some((l) => l.toLowerCase() === label.toLowerCase())) return s return { labelEdits: { removals: { ...s.labelEdits.removals, [emailId]: [...curr, label] }, additions: { ...s.labelEdits.additions, [emailId]: (s.labelEdits.additions[emailId] ?? []).filter( (a) => a.toLowerCase() !== label.toLowerCase() ), }, }, } }), setLabelEdits: (updater) => set((s) => ({ labelEdits: updater(s.labelEdits) })), hideEmail: (id) => set((s) => ({ hiddenEmailIds: s.hiddenEmailIds.includes(id) ? s.hiddenEmailIds : [...s.hiddenEmailIds, id], })), hideEmails: (ids) => set((s) => { const existing = new Set(s.hiddenEmailIds) const toAdd = ids.filter((id) => !existing.has(id)) return toAdd.length > 0 ? { hiddenEmailIds: [...s.hiddenEmailIds, ...toAdd] } : s }), unhideEmail: (id) => set((s) => ({ hiddenEmailIds: s.hiddenEmailIds.filter((x) => x !== id), })), markSeen: (id) => set((s) => ({ seenEmailIds: s.seenEmailIds.includes(id) ? s.seenEmailIds : [...s.seenEmailIds, id], })), resetHidden: () => set({ hiddenEmailIds: [] }), pushRecentMoveTarget: (targetId) => set((s) => { const MAX = 5 const filtered = s.recentMoveTargets.filter((t) => t !== targetId) return { recentMoveTargets: [targetId, ...filtered].slice(0, MAX) } }), pushRecentFolderVisit: (visitKey) => set((s) => { const MAX = 4 const filtered = s.recentFolderVisits.filter((k) => k !== visitKey) return { recentFolderVisits: [visitKey, ...filtered].slice(0, MAX) } }), }), { name: "ultimail-mail-state", version: 2, migrate: (persisted, version) => { const state = persisted as MailStoreState if (version < 2) { return { ...state, recentFolderVisits: [] } } return state }, } ) )