"use client"; import { Portal } from "@/lib/portal/components"; import { atom, useAtom } from "jotai"; import React, { useCallback, useEffect, useState } from "react"; import { ReactNode } from "react"; type toastMessage = { msg: ReactNode; type?: "error" | "default"; fading: boolean; duration?: number; }; type IDToastMessage = toastMessage & { id: string; }; const toastAtom = atom([]); export function useToast() { const [_, setToasts] = useAtom(toastAtom); const createToast = useCallback( (t: toastMessage) => { const idd = { ...t, id: crypto.randomUUID() }; setToasts((toasts) => { return [...toasts, idd]; }); return idd; }, [setToasts] ); const clearToast = useCallback( (t: toastMessage) => setToasts((toasts) => toasts.filter((to) => to != t)), [setToasts] ); return { createToast, clearToast, }; } export function Toaster() { const [toasts, setToasts] = useAtom(toastAtom); const clearToast = useCallback( (t: toastMessage) => { setToasts((toasts) => { return toasts.filter((to) => to !== t); }); }, [setToasts] ); if (!toasts.length) return <>; return (
{toasts.map((t) => ( ))}
); } function Toast(props: { toast: toastMessage; clearToast: (t: toastMessage) => void; }) { const { toast, clearToast } = props; const [fading, setFading] = useState(false); const clear = useCallback(() => { setFading(true); setTimeout(() => { clearToast(toast); }, 300); }, [clearToast, toast]); const fadeOut = useCallback(() => { setTimeout(clear, toast.duration ?? 3000); }, [clear, toast]); useEffect(() => { if (!toast.fading) return; fadeOut(); }, [fadeOut, toast]); return (
{toast.msg} {!toast.fading && ( )}
); }