Files
upstream-plane/apps/web/core/hooks/use-reload-confirmation.tsx
upstream-mirror 23059a1de3
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
2026-09-15 15:14:58 +05:00

68 lines
2.4 KiB
TypeScript

/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useCallback, useEffect, useState } from "react";
//TODO: remove temp flag isActive later and use showAlert as the source of truth
const useReloadConfirmations = (isActive = true, message?: string, defaultShowAlert = false, onLeave?: () => void) => {
const [showAlert, setShowAlert] = useState(defaultShowAlert);
const alertMessage = message ?? "Are you sure you want to leave? Changes you made may not be saved.";
const handleBeforeUnload = useCallback(
(event: BeforeUnloadEvent) => {
if (!isActive || !showAlert) return;
event.preventDefault();
event.returnValue = "";
},
[isActive, showAlert]
);
const handleAnchorClick = useCallback(
(event: MouseEvent) => {
if (!isActive || !showAlert) return;
// Skip if event target is not available or defaultPrevented
if (!event.target || event.defaultPrevented) return;
// Skip control/command/option/alt+click
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
// check if the event target is an anchor or a child of an anchor tag
const eventTarget = event.target as HTMLElement;
if (!eventTarget.closest("a")) return; // This is intentionally not type safe
// check if anchor target is _blank
const anchorElement = eventTarget.closest("a") as HTMLAnchorElement;
const isAnchorTargetBlank = anchorElement.getAttribute("target") === "_blank";
if (isAnchorTargetBlank) return;
// show confirm dialog
const isLeaving = confirm(alertMessage);
if (isLeaving) {
onLeave && onLeave();
} else {
event.preventDefault();
event.stopPropagation();
}
},
[isActive, showAlert]
);
useEffect(() => {
// handle browser refresh
window.addEventListener("beforeunload", handleBeforeUnload, true);
// handle anchor tag click
window.addEventListener("click", handleAnchorClick, true);
// TODO: handle back / forward button click
return () => {
// cleanup
window.removeEventListener("beforeunload", handleBeforeUnload, true);
window.removeEventListener("click", handleAnchorClick, true);
};
}, [handleAnchorClick, handleBeforeUnload]);
return { setShowAlert };
};
export default useReloadConfirmations;