Skip to content
Source
Sign inSign up

thread-composer-error.ts

49 lines1.6 KB

1import { Atom } from "effect/reactivity";
2​
3import { appAtomRegistry } from "./atom-registry";
4​
5interface ThreadComposerError {
6 readonly message: string;
7 readonly messageId: string | null;
8}
9​
10/** Draining can fail after navigation away; retain errors per thread until dismissed, retried, or delivered. */
11export const threadComposerErrorsAtom = Atom.make<Readonly<Record<string, ThreadComposerError>>>(
12 {},
13).pipe(Atom.keepAlive, Atom.withLabel("mobile:thread-composer-errors"));
14​
15export function setThreadComposerError(
16 threadKey: string,
17 message: string,
18 messageId: string | null = null,
19): void {
20 appAtomRegistry.set(threadComposerErrorsAtom, {
21 ...appAtomRegistry.get(threadComposerErrorsAtom),
22 [threadKey]: { message, messageId },
23 });
25​
26export function clearThreadComposerError(threadKey: string, messageId?: string): void {
27 const current = appAtomRegistry.get(threadComposerErrorsAtom);
28 const error = current[threadKey];
29 if (!error || (messageId !== undefined && error.messageId !== messageId)) {
30 return;
31 }
32 const next = { ...current };
33 delete next[threadKey];
34 appAtomRegistry.set(threadComposerErrorsAtom, next);
36​
37export function clearThreadComposerErrorsForEnvironment(environmentId: string): void {
38 const current = appAtomRegistry.get(threadComposerErrorsAtom);
39 const prefix = `${environmentId}:`;
40 const keys = Object.keys(current).filter((key) => key.startsWith(prefix));
41 if (keys.length === 0) {
42 return;
43 }
44 const next = { ...current };
45 for (const key of keys) {
46 delete next[key];
47 }
48 appAtomRegistry.set(threadComposerErrorsAtom, next);