63 lines
1.7 KiB
TypeScript
63 lines
1.7 KiB
TypeScript
import { toastWaiting } from '@/toast';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useCallback, useEffect, useRef, useTransition } from 'react';
|
|
import { FiCheckSquare } from 'react-icons/fi';
|
|
import { toast } from 'sonner';
|
|
|
|
export default function useNavigateOrRunActionWithToast({
|
|
pathOrAction,
|
|
toastMessage = 'Loading...',
|
|
dismissDelay = 1500,
|
|
}: {
|
|
pathOrAction?: string | (() => Promise<any> | undefined)
|
|
toastMessage?: string
|
|
dismissDelay?: number
|
|
}) {
|
|
const router = useRouter();
|
|
|
|
const toastId = useRef<string | number>(undefined);
|
|
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
const dismissToast = useCallback(() => {
|
|
if (toastId.current) {
|
|
toast(toastMessage, {
|
|
id: toastId.current,
|
|
icon: <FiCheckSquare size={16} />,
|
|
});
|
|
return setTimeout(() => {
|
|
toast.dismiss(toastId.current);
|
|
}, dismissDelay);
|
|
}
|
|
}, [dismissDelay, toastMessage]);
|
|
|
|
useEffect(() => {
|
|
if (!isPending) {
|
|
const timeout = dismissToast();
|
|
return () => clearTimeout(timeout);
|
|
}
|
|
return () => {
|
|
dismissToast();
|
|
};
|
|
}, [isPending, dismissDelay, dismissToast]);
|
|
|
|
const navigateOrRunAction = useCallback(() => {
|
|
if (typeof pathOrAction === 'string') {
|
|
startTransition(() => {
|
|
router.push(pathOrAction);
|
|
toastId.current = toastWaiting(toastMessage);
|
|
});
|
|
} else if (typeof pathOrAction === 'function') {
|
|
const result = pathOrAction();
|
|
if (result instanceof Promise) {
|
|
toastId.current = toastWaiting(toastMessage);
|
|
result.finally(() => {
|
|
dismissToast();
|
|
});
|
|
}
|
|
}
|
|
}, [dismissToast, pathOrAction, router, toastMessage]);
|
|
|
|
return navigateOrRunAction;
|
|
}
|