Files
no-copy-frontend/src/app/hooks/useNavigationBlocker.ts
T

81 lines
1.8 KiB
TypeScript

'use client';
import { useEffect } from 'react';
import { useRouter } from 'next/navigation';
interface UseNavigationBlockerProps {
shouldBlock: boolean;
message?: string;
onConfirm?: () => void;
onCancel?: () => void;
}
export const useNavigationBlocker = ({
shouldBlock,
message,
onConfirm,
onCancel
}: UseNavigationBlockerProps) => {
const router = useRouter();
useEffect(() => {
if (!shouldBlock) return;
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
e.preventDefault();
e.returnValue = message;
return message;
};
const handleClick = (e: MouseEvent) => {
const target = e.target as HTMLElement;
const link = target.closest('a');
if (link && link.href) {
const currentUrl = window.location.href;
if (link.href !== currentUrl && !link.href.startsWith('#')) {
e.preventDefault();
e.stopPropagation();
const confirmed = window.confirm(message);
if (confirmed) {
onConfirm?.();
window.location.href = link.href;
} else {
onCancel?.();
}
}
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
document.addEventListener('click', handleClick, true);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
document.removeEventListener('click', handleClick, true);
};
}, [shouldBlock, message, onConfirm, onCancel]);
useEffect(() => {
if (!shouldBlock) return;
const originalPush = router.push;
router.push = async (...args) => {
const confirmed = window.confirm(message);
if (confirmed) {
onConfirm?.();
return originalPush.apply(router, args);
} else {
onCancel?.();
return Promise.resolve(false);
}
};
return () => {
router.push = originalPush;
};
}, [shouldBlock, message, router, onConfirm, onCancel]);
};