Files
cinny/src/app/state/toast.ts
T

47 lines
1.5 KiB
TypeScript
Raw Normal View History

import { atom } from 'jotai';
import type { IconSrc } from 'folds';
export type ToastNotif = {
id: string;
avatarUrl?: string;
iconSrc?: IconSrc; // folds Icon src for a "system" toast (shown instead of an avatar/initials)
displayName: string;
body: string;
roomName: string;
roomId: string;
hashPath?: string; // overrides window.location.hash navigation when set
onClick?: () => void; // custom click handler; skips hash navigation when set
sticky?: boolean; // when true, does not auto-dismiss — use for action toasts that require a click
};
// Build a "download complete" system toast. Kept folds-free here (the icon src is
// passed in) so this stays a pure, testable builder. roomId is empty + onClick is
// set so a click only dismisses (never navigates to a room).
export const createDownloadToast = (filename: string, iconSrc?: IconSrc): ToastNotif => ({
id: `download-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
displayName: 'Downloaded',
body: filename,
roomName: '',
roomId: '',
iconSrc,
onClick: () => undefined,
});
const baseAtom = atom<ToastNotif[]>([]);
// Write-only setter used in ClientNonUIFeatures
export const toastQueueAtom = atom<ToastNotif[], [ToastNotif | null], void>(
(get) => get(baseAtom),
(get, set, notif) => {
if (notif === null) return; // no-op guard
set(baseAtom, [...get(baseAtom), notif]);
},
);
export const dismissToastAtom = atom<null, [string], void>(null, (get, set, id) =>
set(
baseAtom,
get(baseAtom).filter((t) => t.id !== id),
),
);