| 1 | import type { InboxQueueEdit } from "./inboxQueueCommands"; |
| 2 | import type { InboxTarget } from "./pendingFollowup"; |
| 3 | |
| 4 | export type QueueEditDraft = InboxQueueEdit & { target: InboxTarget; value: string; reason?: string }; |
| 5 | export type QueueDraftState = { edit?: QueueEditDraft; recovered: QueueEditDraft[] }; |
| 6 | const empty: QueueDraftState = { recovered: [] }; |
| 7 | const states = new Map<string, QueueDraftState>(); |
| 8 | const listeners = new Set<() => void>(); |
| 9 | const storageKey = (scope: string) => `reasonix.inbox-edit.v1:${scope}`; |
| 10 | |
| 11 | // Separate from the main composer draft: switching tasks or closing the edit |
| 12 | // view cannot overwrite either piece of user input. No requests are replayed. |
| 13 | export const inboxQueueDrafts = { |
| 14 | subscribe(fn: () => void) { listeners.add(fn); return () => { listeners.delete(fn); }; }, |
| 15 | get(scope: string): QueueDraftState { |
| 16 | if (!scope) return empty; |
| 17 | if (!states.has(scope)) { |
| 18 | let state = empty; |
| 19 | try { |
| 20 | const parsed = JSON.parse(sessionStorage.getItem(storageKey(scope)) || "null"); |
| 21 | if (parsed && Array.isArray(parsed.recovered) && (!parsed.edit || (typeof parsed.edit.value === "string" && parsed.edit.target))) state = parsed; |
| 22 | } catch { /* The in-memory draft remains available when storage is disabled. */ } |
| 23 | states.set(scope, state); |
| 24 | } |
| 25 | return states.get(scope)!; |
| 26 | }, |
| 27 | set(scope: string, state: QueueDraftState) { |
| 28 | if (!scope) return; |
| 29 | states.set(scope, state); |
| 30 | try { sessionStorage.setItem(storageKey(scope), JSON.stringify(state)); } catch { /* Keep the live draft. */ } |
| 31 | listeners.forEach(fn => fn()); |
| 32 | }, |
| 33 | }; |
| 34 |