mirror of
https://bitbucket.org/Mattrixwv/mattrixwvreactcomponents.git
synced 2025-12-06 21:53:57 -05:00
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import { DangerMessageBlock, SuccessMessageBlock, WarningMessageBlock } from "$/component/message";
|
|
import Toaster from "$/component/toaster/Toaster";
|
|
import type { Toast, ToastProviderProps, ToastProviderState } from "$/types/ToasterTypes";
|
|
import moment from "moment";
|
|
import { createContext, useCallback, useContext, useMemo, useState } from "react";
|
|
|
|
|
|
const toastInitialState: ToastProviderState = {
|
|
toast: [],
|
|
hideToast: () => {},
|
|
addToast: () => "",
|
|
addSuccess: () => "",
|
|
addWarning: () => "",
|
|
addDanger: () => ""
|
|
};
|
|
|
|
const ToasterProviderContext = createContext<ToastProviderState>(toastInitialState);
|
|
|
|
|
|
export default function ToasterProvider({
|
|
className,
|
|
children
|
|
}: ToastProviderProps){
|
|
const [ toast, setToast ] = useState<Toast[]>([]);
|
|
|
|
|
|
const hideToast = useCallback(function hide(id: string){
|
|
setToast((prev) => {
|
|
if(prev.length === 1 && prev[0].id === id){
|
|
const current = prev[0].hideTime > moment(new Date()).subtract(600, "ms").toDate() ? [...prev] : [];
|
|
if(current.length > 0){
|
|
setTimeout(() => hide(id), 600);
|
|
}
|
|
return current;
|
|
}
|
|
else{
|
|
return prev.filter((toast) => toast.id !== id);
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
const addToast = useCallback((message: React.ReactNode, duration?: number) => {
|
|
if(!duration){
|
|
duration = 5000;
|
|
}
|
|
const id = crypto.randomUUID();
|
|
|
|
setToast((prev) => [ ...prev, { id, message, duration, hideTime: moment(new Date()).add(duration, "ms").toDate() } ]);
|
|
setTimeout(() => hideToast(id), duration);
|
|
|
|
return id;
|
|
}, [hideToast]);
|
|
|
|
const addSuccess = useCallback((message: React.ReactNode, duration?: number) => {
|
|
return addToast(<SuccessMessageBlock>{message}</SuccessMessageBlock>, duration);
|
|
}, [ addToast ]);
|
|
|
|
const addWarning = useCallback((message: React.ReactNode, duration?: number) => {
|
|
return addToast(<WarningMessageBlock>{message}</WarningMessageBlock>, duration);
|
|
}, [ addToast ]);
|
|
|
|
const addDanger = useCallback((message: React.ReactNode, duration?: number) => {
|
|
return addToast(<DangerMessageBlock>{message}</DangerMessageBlock>, duration);
|
|
}, [ addToast ]);
|
|
|
|
const value: ToastProviderState = useMemo(() => ({
|
|
toast,
|
|
hideToast,
|
|
addToast,
|
|
addSuccess,
|
|
addWarning,
|
|
addDanger
|
|
}), [ toast, hideToast, addToast, addSuccess, addWarning, addDanger ]);
|
|
|
|
return (
|
|
<ToasterProviderContext.Provider value={value}>
|
|
<Toaster
|
|
toast={toast}
|
|
className={className}
|
|
/>
|
|
{children}
|
|
</ToasterProviderContext.Provider>
|
|
);
|
|
}
|
|
|
|
|
|
// eslint-disable-next-line react-refresh/only-export-components
|
|
export function useToaster(){
|
|
const context = useContext(ToasterProviderContext);
|
|
|
|
if(!context){
|
|
throw new Error("useToaster must be used within a ToasterProvider");
|
|
}
|
|
|
|
return context;
|
|
}
|