67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
|
/**
|
||
|
* External dependencies
|
||
|
*/
|
||
|
import { useContext, useEffect, useMemo } from '@wordpress/element';
|
||
|
import { __ } from '@wordpress/i18n';
|
||
|
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom';
|
||
|
|
||
|
export default function usePreventLeavingPage(
|
||
|
hasUnsavedChanges: boolean,
|
||
|
/**
|
||
|
* Some browsers ignore this message currently on before unload event.
|
||
|
*
|
||
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#compatibility_notes
|
||
|
*/
|
||
|
message?: string
|
||
|
) {
|
||
|
const confirmMessage = useMemo(
|
||
|
() =>
|
||
|
message ??
|
||
|
__( 'Changes you made may not be saved.', 'woocommerce' ),
|
||
|
[ message ]
|
||
|
);
|
||
|
const { navigator } = useContext( NavigationContext );
|
||
|
|
||
|
// This effect prevent react router from navigate and show
|
||
|
// a confirmation message. It's a work around to beforeunload
|
||
|
// because react router does not triggers that event.
|
||
|
useEffect( () => {
|
||
|
if ( hasUnsavedChanges ) {
|
||
|
const push = navigator.push;
|
||
|
|
||
|
navigator.push = ( ...args: Parameters< typeof push > ) => {
|
||
|
/* eslint-disable-next-line no-alert */
|
||
|
const result = window.confirm( confirmMessage );
|
||
|
if ( result !== false ) {
|
||
|
push( ...args );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return () => {
|
||
|
navigator.push = push;
|
||
|
};
|
||
|
}
|
||
|
}, [ navigator, hasUnsavedChanges, confirmMessage ] );
|
||
|
|
||
|
// This effect listen to the native beforeunload event to show
|
||
|
// a confirmation message
|
||
|
useEffect( () => {
|
||
|
if ( hasUnsavedChanges ) {
|
||
|
function onBeforeUnload( event: BeforeUnloadEvent ) {
|
||
|
event.preventDefault();
|
||
|
return ( event.returnValue = confirmMessage );
|
||
|
}
|
||
|
|
||
|
window.addEventListener( 'beforeunload', onBeforeUnload, {
|
||
|
capture: true,
|
||
|
} );
|
||
|
|
||
|
return () => {
|
||
|
window.removeEventListener( 'beforeunload', onBeforeUnload, {
|
||
|
capture: true,
|
||
|
} );
|
||
|
};
|
||
|
}
|
||
|
}, [ hasUnsavedChanges, confirmMessage ] );
|
||
|
}
|