diff --git a/frontend/src/stores/mail.test.ts b/frontend/src/stores/mail.test.ts index 17e7a3a..4436b54 100644 --- a/frontend/src/stores/mail.test.ts +++ b/frontend/src/stores/mail.test.ts @@ -86,6 +86,74 @@ describe('mail store', () => { }) }) + it('deletes selected mail in one batch and reloads the remaining entries', async () => { + const remaining = listItem(3) + mockNuiCall + .mockResolvedValueOnce({ success: true }) + .mockResolvedValueOnce({ data: counts, success: true }) + .mockResolvedValueOnce({ + data: { hasMore: false, items: [remaining], offset: 0 }, + success: true, + }) + + const mail = useMailStore() + mail.folder = 'sent' + mail.search = 'plans' + mail.items = [listItem(1), listItem(2), remaining] + + const success = await mail.deleteMany([1, 2]) + + expect(success).toBe(true) + expect(mockNuiCall).toHaveBeenCalledTimes(3) + expect(mockNuiCall).toHaveBeenNthCalledWith(1, 'mail:delete-many', { + folder: 'sent', + ids: [1, 2], + }) + expect(mockNuiCall).toHaveBeenNthCalledWith(2, 'mail:counts') + expect(mockNuiCall).toHaveBeenNthCalledWith(3, 'mail:list', { + folder: 'sent', + offset: 0, + search: 'plans', + }) + expect(mail.items.map((item) => item.id)).toEqual([3]) + }) + + it('does not refresh a cleared session after a batch delete returns', async () => { + let resolveDelete!: (response: NuiResponse) => void + mockNuiCall.mockReturnValueOnce( + new Promise((resolve) => { + resolveDelete = resolve + }), + ) + const mail = useMailStore() + + const deletion = mail.deleteMany([1, 2]) + await mail.bootstrap('') + resolveDelete({ success: true }) + + expect(await deletion).toBe(true) + expect(mockNuiCall).toHaveBeenCalledTimes(1) + }) + + it('sends the mail read state with the server contract field', async () => { + mockNuiCall + .mockResolvedValueOnce({ success: true }) + .mockResolvedValueOnce({ data: counts, success: true }) + .mockResolvedValueOnce({ + data: { hasMore: false, items: [listItem(2)], offset: 0 }, + success: true, + }) + const mail = useMailStore() + + expect(await mail.mutateEntry('mail:set-read', 2, { read: true })).toBe( + true, + ) + expect(mockNuiCall).toHaveBeenNthCalledWith(1, 'mail:set-read', { + id: 2, + read: true, + }) + }) + it('logs out the active session and resets mailbox state', async () => { mockNuiCall .mockResolvedValueOnce({ diff --git a/frontend/src/stores/mail.ts b/frontend/src/stores/mail.ts index 01a4c5b..d9ac1e8 100644 --- a/frontend/src/stores/mail.ts +++ b/frontend/src/stores/mail.ts @@ -209,6 +209,21 @@ export const useMailStore = defineStore('mail', () => { return response.success } + async function deleteMany(ids: Array): Promise { + const activeFolder = folder.value + const session = sessionGeneration + const response = await nuiCall('mail:delete-many', { + folder: activeFolder, + ids, + }) + if (!response.success || session !== sessionGeneration) { + return response.success + } + + await Promise.all([refreshCounts(), loadFolder(folder.value, search.value)]) + return true + } + async function emptyTrash(): Promise { const response = await nuiCall('mail:empty-trash') if (response.success) { @@ -222,6 +237,7 @@ export const useMailStore = defineStore('mail', () => { bootstrap, counts, deleteDraft, + deleteMany, emptyTrash, folder, hasMore, diff --git a/frontend/src/types/mail.ts b/frontend/src/types/mail.ts index 2815d2a..87010da 100644 --- a/frontend/src/types/mail.ts +++ b/frontend/src/types/mail.ts @@ -1,3 +1,5 @@ +import type { DatabaseDateValue } from '@/utils/date' + export type MailFolder = 'inbox' | 'sent' | 'drafts' | 'trash' export type MailCounts = { @@ -10,7 +12,7 @@ export type MailCounts = { export type MailListItem = { body?: string - created_at: string + created_at: DatabaseDateValue folder?: 'inbox' | 'sent' id: number | string is_read?: boolean @@ -33,7 +35,7 @@ export type MailMessage = MailListItem & { export type MailDraft = { body: string - created_at: string + created_at: DatabaseDateValue id: string recipients: string[] subject: string diff --git a/frontend/src/views/apps/MailApp.vue b/frontend/src/views/apps/MailApp.vue index 40fa532..493f544 100644 --- a/frontend/src/views/apps/MailApp.vue +++ b/frontend/src/views/apps/MailApp.vue @@ -1,7 +1,20 @@