UNPKG

ra-core

Version:

Core components of react-admin, a frontend Framework for building admin applications on top of REST services, using ES6, React

80 lines 4.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useWarnWhenUnsavedChanges = void 0; var react_1 = require("react"); var react_hook_form_1 = require("react-hook-form"); var react_router_dom_1 = require("react-router-dom"); var i18n_1 = require("../i18n"); /** * Display a confirmation dialog if the form has unsaved changes. * - If the user confirms, the navigation continues and the changes are lost. * - If the user cancels, the navigation is cancelled and the changes are kept. */ var useWarnWhenUnsavedChanges = function (enable, formRootPathname, control) { var translate = (0, i18n_1.useTranslate)(); var _a = (0, react_hook_form_1.useFormState)(control ? { control: control } : undefined), isSubmitSuccessful = _a.isSubmitSuccessful, dirtyFields = _a.dirtyFields; var isDirty = Object.keys(dirtyFields).length > 0; var _b = (0, react_1.useState)(false), shouldNotify = _b[0], setShouldNotify = _b[1]; var shouldNotBlock = !enable || !isDirty || isSubmitSuccessful; var blocker = (0, react_router_dom_1.useBlocker)(function (_a) { var currentLocation = _a.currentLocation, nextLocation = _a.nextLocation; if (shouldNotBlock) return false; // Also check if the new location is inside the form var initialLocation = formRootPathname || currentLocation.pathname; var newLocationIsInsideCurrentLocation = nextLocation.pathname.startsWith(initialLocation); var newLocationIsShowView = nextLocation.pathname.startsWith("".concat(initialLocation, "/show")); var newLocationIsInsideForm = newLocationIsInsideCurrentLocation && !newLocationIsShowView; if (newLocationIsInsideForm) return false; return true; }); (0, react_1.useEffect)(function () { if (blocker.state === 'blocked') { // Corner case: the blocker might be triggered by a redirect in the onSuccess side effect, // happening during the same tick the form is reset after a successful save. // In that case, the blocker will block but shouldNotBlock will be true one tick after. // If we are in that case, we can proceed immediately. if (shouldNotBlock) { blocker.proceed(); return; } setShouldNotify(true); } // This effect should only run when the blocker state changes, not when shouldNotBlock changes. // eslint-disable-next-line react-hooks/exhaustive-deps }, [blocker.state]); (0, react_1.useEffect)(function () { if (shouldNotify) { var shouldProceed = window.confirm(translate('ra.message.unsaved_changes')); if (shouldProceed) { blocker.proceed && blocker.proceed(); } else { blocker.reset && blocker.reset(); } } setShouldNotify(false); // Can't use blocker in the dependency array because it is not stable across rerenders // eslint-disable-next-line react-hooks/exhaustive-deps }, [shouldNotify, translate]); // This effect handles document navigation, e.g. closing the tab (0, react_1.useEffect)(function () { var beforeunload = function (e) { // Invoking event.preventDefault() will trigger a warning dialog when the user closes or navigates the tab // https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#examples e.preventDefault(); // Included for legacy support, e.g. Chrome/Edge < 119 e.returnValue = true; }; if (shouldNotBlock) { return; } window.addEventListener('beforeunload', beforeunload); return function () { window.removeEventListener('beforeunload', beforeunload); }; }, [shouldNotBlock]); }; exports.useWarnWhenUnsavedChanges = useWarnWhenUnsavedChanges; //# sourceMappingURL=useWarnWhenUnsavedChanges.js.map