import type { History, Blocker, Transition } from 'history'; import { useEffect } from 'react'; // see: https://gist.github.com/rmorse/426ffcc579922a82749934826fa9f743 import { Navigator as BaseNavigator } from 'react-router-dom'; interface Navigator extends BaseNavigator { block?: History['block']; } export interface FormBasedPreventNavigationProps { promptMessage?: string; preventNavigate: boolean; navigator: Navigator; } /** Only use this if the project uses `` or any router that does not support the new * [react-router Data API](https://reactrouter.com/en/main/routers/picking-a-router#using-v64-data-apis) * * Legacy function to prevent the user from navigating away from a form if there are any changes. */ export default function LegacyFormBasedPreventNavigation({ promptMessage = 'Changes you made may not be saved.', preventNavigate, navigator, }: FormBasedPreventNavigationProps) { useEffect(() => { if (!preventNavigate) { return; } let unblock = () => {}; const push = navigator.push; // TODO: https://reactrouter.com/docs/en/v6/upgrading/v5#prompt-is-not-currently-supported // this is a workaround until we get native support for prompt on navigate if (navigator.block) { const blocker: Blocker = (tx) => { if (window.confirm(promptMessage)) { tx.retry(); } }; unblock = navigator.block((tx: Transition) => { const autoUnblockingTx = { ...tx, retry() { // Automatically unblock the transition so it can play all the way // through before retrying it. TODO: Figure out how to re-enable // this block if the transition is cancelled for some reason. unblock(); tx.retry(); }, }; blocker(autoUnblockingTx); }); } else { //https://gist.github.com/MarksCode/64e438c82b0b2a1161e01c88ca0d0355 navigator.push = (...args: Parameters) => { if (window.confirm(promptMessage)) { push(...args); } }; } window.addEventListener('beforeunload', beforeUnload); return () => { unblock(); navigator.push = push; window.removeEventListener('beforeunload', beforeUnload); }; function beforeUnload(e: BeforeUnloadEvent) { e.preventDefault(); e.returnValue = promptMessage; } }, [preventNavigate, promptMessage, navigator]); return null; }