Files
chat_room/admin/src/components/ui/Toast.tsx
T

66 lines
1.9 KiB
TypeScript
Raw Normal View History

"use client";
import {
createContext,
useCallback,
useContext,
useState,
ReactNode,
} from "react";
import { CheckCircle2, XCircle } from "lucide-react";
interface Toast {
id: number;
message: string;
tone: "success" | "error";
}
interface ToastContextValue {
showSuccess: (message: string) => void;
showError: (message: string) => void;
}
const ToastContext = createContext<ToastContextValue | null>(null);
let idCounter = 0;
export function ToastProvider({ children }: { children: ReactNode }) {
const [toasts, setToasts] = useState<Toast[]>([]);
const push = useCallback((message: string, tone: Toast["tone"]) => {
const id = ++idCounter;
setToasts((prev) => [...prev, { id, message, tone }]);
setTimeout(() => {
setToasts((prev) => prev.filter((t) => t.id !== id));
}, 3500);
}, []);
const showSuccess = useCallback((m: string) => push(m, "success"), [push]);
const showError = useCallback((m: string) => push(m, "error"), [push]);
return (
<ToastContext.Provider value={{ showSuccess, showError }}>
{children}
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[100] flex flex-col gap-2 items-center">
{toasts.map((t) => (
<div
key={t.id}
className={`flex items-center gap-2 rounded-(--radius-md) px-4 py-3 shadow-(--shadow-cute-lg) text-[13px] font-semibold text-white [animation:bounce-in_0.3s_ease-out] ${
t.tone === "success" ? "bg-(--color-status-success)" : "bg-(--color-status-error)"
}`}
>
{t.tone === "success" ? <CheckCircle2 size={16} /> : <XCircle size={16} />}
{t.message}
</div>
))}
</div>
</ToastContext.Provider>
);
}
export function useToast() {
const ctx = useContext(ToastContext);
if (!ctx) throw new Error("useToast باید داخل ToastProvider استفاده بشه");
return ctx;
}