75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
|
|
import React, { createContext, useContext, useState, ReactNode } from "react";
|
||
|
|
|
||
|
|
type Toast = {
|
||
|
|
id: string;
|
||
|
|
message: string;
|
||
|
|
type: "success" | "error" | "info" | "warning";
|
||
|
|
position?: ToastPosition; // Optional position for each toast
|
||
|
|
};
|
||
|
|
|
||
|
|
type ToastPosition =
|
||
|
|
| "top-left"
|
||
|
|
| "top-center"
|
||
|
|
| "top-right"
|
||
|
|
| "bottom-left"
|
||
|
|
| "bottom-center"
|
||
|
|
| "bottom-right";
|
||
|
|
|
||
|
|
type ToastContextType = {
|
||
|
|
addToast: (
|
||
|
|
message: string,
|
||
|
|
type: Toast["type"],
|
||
|
|
position?: ToastPosition
|
||
|
|
) => void;
|
||
|
|
removeToast: (id: string) => void;
|
||
|
|
};
|
||
|
|
|
||
|
|
const ToastContext = createContext<ToastContextType | undefined>(undefined);
|
||
|
|
|
||
|
|
const ToastProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||
|
|
const [toasts, setToasts] = useState<Toast[]>([]);
|
||
|
|
|
||
|
|
const addToast = (
|
||
|
|
message: string,
|
||
|
|
type: Toast["type"],
|
||
|
|
position: ToastPosition = "bottom-center" // Default position
|
||
|
|
) => {
|
||
|
|
const id = Math.random().toString(36).substr(2, 9); // Generate a unique ID
|
||
|
|
setToasts((prev) => [...prev, { id, message, type, position }]);
|
||
|
|
|
||
|
|
// Auto-remove toast after 3 seconds
|
||
|
|
setTimeout(() => removeToast(id), 3000);
|
||
|
|
};
|
||
|
|
|
||
|
|
const removeToast = (id: string) => {
|
||
|
|
setToasts((prev) => prev.filter((toast) => toast.id !== id));
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<ToastContext.Provider value={{ addToast, removeToast }}>
|
||
|
|
{children}
|
||
|
|
<div className={`toast-container ${"bottom-center"}`}>
|
||
|
|
{toasts.map((toast) => (
|
||
|
|
<div
|
||
|
|
key={toast.id}
|
||
|
|
className={`toast ${toast.type}`}
|
||
|
|
onClick={() => removeToast(toast.id)} // Allow manual dismissal
|
||
|
|
>
|
||
|
|
{toast.message}
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</ToastContext.Provider>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export const useToast = (): ToastContextType => {
|
||
|
|
const context = useContext(ToastContext);
|
||
|
|
if (!context) {
|
||
|
|
throw new Error("useToast must be used within a ToastProvider");
|
||
|
|
}
|
||
|
|
return context;
|
||
|
|
};
|
||
|
|
|
||
|
|
export default ToastProvider;
|