feat: v0.17.0 — ISS-008 toasts for errors/events + browser notifications
CI / build + unit + e2e (pull_request) Failing after 6m59s
CI / build + unit + e2e (pull_request) Failing after 6m59s
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
// ISS-008 (v0.17.0): transient toast notifications — a bottom-right stack for action errors
|
||||
// and game events derived from snapshot diffs. Each toast auto-dismisses after TOAST_TTL_MS;
|
||||
// the queue is capped at MAX_TOASTS (oldest dropped) so an event burst can't fill the corner.
|
||||
|
||||
export type ToastKind = 'error' | 'info';
|
||||
|
||||
export interface Toast {
|
||||
id: number;
|
||||
kind: ToastKind;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const TOAST_TTL_MS = 5_000;
|
||||
export const MAX_TOASTS = 4;
|
||||
|
||||
// Pure core (unit-tested): append a toast, dropping the oldest beyond the cap.
|
||||
export function pushToast(toasts: Toast[], toast: Toast): Toast[] {
|
||||
return [...toasts, toast].slice(-MAX_TOASTS);
|
||||
}
|
||||
|
||||
export interface UseToastsResult {
|
||||
toasts: Toast[];
|
||||
push: (kind: ToastKind, message: string) => void;
|
||||
dismiss: (id: number) => void;
|
||||
}
|
||||
|
||||
export function useToasts(): UseToastsResult {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
const nextIdRef = useRef(1);
|
||||
|
||||
// Functional update — a late timer for an already-dismissed/dropped id is a no-op.
|
||||
const dismiss = useCallback((id: number) => {
|
||||
setToasts((current) => current.filter((t) => t.id !== id));
|
||||
}, []);
|
||||
|
||||
const push = useCallback(
|
||||
(kind: ToastKind, message: string) => {
|
||||
const toast: Toast = { id: nextIdRef.current++, kind, message };
|
||||
setToasts((current) => pushToast(current, toast));
|
||||
setTimeout(() => dismiss(toast.id), TOAST_TTL_MS);
|
||||
},
|
||||
[dismiss],
|
||||
);
|
||||
|
||||
return { toasts, push, dismiss };
|
||||
}
|
||||
Reference in New Issue
Block a user