54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
import { createContext, useCallback, useContext, useEffect, useRef, useState, type ReactNode } from 'react';
|
|
import { registerPartnerToastListener, type PartnerToastVariant } from '../lib/toast';
|
|
|
|
type PartnerToastContextValue = {
|
|
showToast: (message: string, variant?: PartnerToastVariant) => void;
|
|
};
|
|
|
|
const PartnerToastContext = createContext<PartnerToastContextValue | null>(null);
|
|
|
|
export function PartnerToastProvider({ children }: { children: ReactNode }) {
|
|
const [toast, setToast] = useState('');
|
|
const [variant, setVariant] = useState<PartnerToastVariant>('success');
|
|
const timerRef = useRef<number | null>(null);
|
|
|
|
const showToast = useCallback((message: string, nextVariant: PartnerToastVariant = 'success') => {
|
|
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
setVariant(nextVariant);
|
|
setToast(message);
|
|
timerRef.current = window.setTimeout(() => {
|
|
setToast('');
|
|
timerRef.current = null;
|
|
}, nextVariant === 'error' ? 3000 : 2000);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
registerPartnerToastListener(showToast);
|
|
return () => {
|
|
registerPartnerToastListener(null);
|
|
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
};
|
|
}, [showToast]);
|
|
|
|
return (
|
|
<PartnerToastContext.Provider value={{ showToast }}>
|
|
{children}
|
|
{toast ? (
|
|
<div
|
|
className={`partner-toast${variant === 'error' ? ' partner-toast--error' : ''}`}
|
|
role="alert"
|
|
aria-live="assertive"
|
|
>
|
|
{toast}
|
|
</div>
|
|
) : null}
|
|
</PartnerToastContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function usePartnerToast(): PartnerToastContextValue {
|
|
const ctx = useContext(PartnerToastContext);
|
|
if (!ctx) throw new Error('usePartnerToast 必须在 PartnerToastProvider 内使用');
|
|
return ctx;
|
|
}
|