feat: add frontend/src/store/mailStore.ts

This commit is contained in:
zio 2026-06-01 22:13:01 +09:00
parent 1716c52354
commit 0237fe6604

View File

@ -0,0 +1,75 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
export interface Folder { name: string; display: string; unread: number; total: number }
export interface MailSummary {
uid: string; subject: string; sender: string; sender_addr: string
date: string; is_read: boolean; has_attachment: boolean; size: number; preview: string
}
export interface MailDetail extends MailSummary {
to: string; cc: string; body_text: string; body_html: string
attachments: { part_id: string; filename: string; content_type: string; size: number }[]
}
interface MailStore {
token: string | null
username: string
displayName: string
folders: Folder[]
currentFolder: string
messages: MailSummary[]
totalMessages: number
currentPage: number
selectedMail: MailDetail | null
loading: boolean
searchQuery: string
composeOpen: boolean
replyTo: MailDetail | null
setToken: (token: string, username: string, displayName: string) => void
logout: () => void
setFolders: (f: Folder[]) => void
setCurrentFolder: (f: string) => void
setMessages: (m: MailSummary[], total: number, page: number) => void
setSelectedMail: (m: MailDetail | null) => void
setLoading: (v: boolean) => void
setSearchQuery: (q: string) => void
openCompose: (replyTo?: MailDetail | null) => void
closeCompose: () => void
markRead: (uid: string) => void
removeMessage: (uid: string) => void
}
export const useMailStore = create<MailStore>()(
persist(
(set) => ({
token: null, username: '', displayName: '',
folders: [], currentFolder: 'INBOX',
messages: [], totalMessages: 0, currentPage: 1,
selectedMail: null, loading: false,
searchQuery: '', composeOpen: false, replyTo: null,
setToken: (token, username, displayName) => set({ token, username, displayName }),
logout: () => set({ token: null, username: '', displayName: '', messages: [], selectedMail: null }),
setFolders: (folders) => set({ folders }),
setCurrentFolder: (currentFolder) => set({ currentFolder, messages: [], selectedMail: null, currentPage: 1 }),
setMessages: (messages, totalMessages, currentPage) => set({ messages, totalMessages, currentPage }),
setSelectedMail: (selectedMail) => set({ selectedMail }),
setLoading: (loading) => set({ loading }),
setSearchQuery: (searchQuery) => set({ searchQuery }),
openCompose: (replyTo = null) => set({ composeOpen: true, replyTo }),
closeCompose: () => set({ composeOpen: false, replyTo: null }),
markRead: (uid) => set(s => ({
messages: s.messages.map(m => m.uid === uid ? { ...m, is_read: true } : m),
folders: s.folders.map(f =>
f.name === s.currentFolder ? { ...f, unread: Math.max(0, f.unread - 1) } : f
),
})),
removeMessage: (uid) => set(s => ({
messages: s.messages.filter(m => m.uid !== uid),
selectedMail: s.selectedMail?.uid === uid ? null : s.selectedMail,
})),
}),
{ name: 'zioinfo-mail', partialize: s => ({ token: s.token, username: s.username, displayName: s.displayName }) }
)
)