woocommerce/plugins/woocommerce-admin/client/hooks/usePreventLeavingPage.ts

67 lines
1.8 KiB
TypeScript
Raw Normal View History

/**
* 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 ] );
}