Some checks failed
E2E / Playwright e2e (push) Has been cancelled
Move mail, compose, contacts, and accounts off mocks onto REST + WS. Add client, auth store, IDB-backed query cache, offline queue, and sync bar; hybrid Zustand for UI-only state. Settings still local until backend has preferences API.
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
"use client"
|
|
|
|
import { create } from "zustand"
|
|
import { persist } from "zustand/middleware"
|
|
import { debouncedPersistJSONStorage } from "@/lib/stores/debounced-json-storage"
|
|
import type { Email } from "@/lib/email-data"
|
|
|
|
export interface OutboxEntry {
|
|
id: string
|
|
account_id: string
|
|
status: "queued" | "scheduled" | "sending" | "sent" | "failed" | "cancelled"
|
|
subject: string
|
|
to: { name: string; address: string }[]
|
|
scheduled_at?: string
|
|
created_at: string
|
|
}
|
|
|
|
type ScheduledStoreState = {
|
|
scheduledEmails: OutboxEntry[]
|
|
snoozedEmails: Email[]
|
|
}
|
|
|
|
type ScheduledStoreActions = {
|
|
addScheduledEmail: (entry: OutboxEntry) => void
|
|
updateScheduledStatus: (id: string, status: OutboxEntry["status"]) => void
|
|
removeScheduled: (id: string) => void
|
|
snoozeMailboxEmail: (row: Email) => void
|
|
restoreSnoozedToInbox: (row: Email) => void
|
|
}
|
|
|
|
export const useScheduledStore = create<ScheduledStoreState & ScheduledStoreActions>()(
|
|
persist(
|
|
(set) => ({
|
|
scheduledEmails: [],
|
|
snoozedEmails: [],
|
|
|
|
addScheduledEmail: (entry) =>
|
|
set((s) => ({
|
|
scheduledEmails: [entry, ...s.scheduledEmails.filter((e) => e.id !== entry.id)],
|
|
})),
|
|
|
|
updateScheduledStatus: (id, status) =>
|
|
set((s) => ({
|
|
scheduledEmails: s.scheduledEmails.map((e) =>
|
|
e.id === id ? { ...e, status } : e
|
|
),
|
|
})),
|
|
|
|
removeScheduled: (id) =>
|
|
set((s) => ({
|
|
scheduledEmails: s.scheduledEmails.filter((e) => e.id !== id),
|
|
})),
|
|
|
|
snoozeMailboxEmail: (row) =>
|
|
set((s) => {
|
|
const persistedId = row.id.startsWith("snz-") ? row.id : `snz-${row.id}`
|
|
const wake = new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
const wakeIso = wake.toISOString()
|
|
const copy: Email = {
|
|
...row,
|
|
id: persistedId,
|
|
labels: ["snoozed"],
|
|
snoozeWakeAt: wakeIso,
|
|
scheduledSendAt: undefined,
|
|
scheduledToName: undefined,
|
|
read: true,
|
|
}
|
|
return {
|
|
snoozedEmails: [
|
|
copy,
|
|
...s.snoozedEmails.filter((e) => e.id !== persistedId),
|
|
],
|
|
}
|
|
}),
|
|
|
|
restoreSnoozedToInbox: (row) =>
|
|
set((s) => ({
|
|
snoozedEmails: s.snoozedEmails.filter((e) => e.id !== row.id),
|
|
})),
|
|
}),
|
|
{
|
|
name: "ultimail-scheduled-state",
|
|
storage: debouncedPersistJSONStorage,
|
|
version: 2,
|
|
migrate: (persisted) => {
|
|
const state = persisted as Record<string, unknown>
|
|
return {
|
|
scheduledEmails: [],
|
|
snoozedEmails: Array.isArray(state.snoozedEmails) ? state.snoozedEmails : [],
|
|
}
|
|
},
|
|
}
|
|
)
|
|
)
|