[WEB-1610] chore: re-implement reload confirmation hook. (#4880)

* [WEB-1610] chore: re-implement reload confirmation hook.

* chore: attach anchor event listner to window instead of body.
This commit is contained in:
Prateek Shourya 2024-06-20 12:19:29 +05:30 committed by GitHub
parent e04eb1a63d
commit 718453b332
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 41 deletions

View file

@ -2,14 +2,12 @@
// @ts-nocheck // @ts-nocheck
import { NodeViewWrapper } from "@tiptap/react"; import { NodeViewWrapper } from "@tiptap/react";
import { cn } from "src/lib/utils"; import { cn } from "src/lib/utils";
import { useRouter } from "next/navigation";
import { IMentionHighlight } from "src/types/mention-suggestion"; import { IMentionHighlight } from "src/types/mention-suggestion";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
// eslint-disable-next-line import/no-anonymous-default-export // eslint-disable-next-line import/no-anonymous-default-export
export const MentionNodeView = (props) => { export const MentionNodeView = (props) => {
// TODO: move it to web app // TODO: move it to web app
const router = useRouter();
const [highlightsState, setHighlightsState] = useState<IMentionHighlight[]>(); const [highlightsState, setHighlightsState] = useState<IMentionHighlight[]>();
useEffect(() => { useEffect(() => {
@ -21,25 +19,20 @@ export const MentionNodeView = (props) => {
hightlights(); hightlights();
}, [props.extension.options]); }, [props.extension.options]);
const handleClick = () => {
if (!props.extension.options.readonly) {
router.push(props.node.attrs.redirect_uri);
}
};
return ( return (
<NodeViewWrapper className="mention-component inline w-fit"> <NodeViewWrapper className="mention-component inline w-fit">
<span <a
href={props.node.attrs.redirect_uri}
target="_blank"
className={cn("mention rounded bg-custom-primary-100/20 px-1 py-0.5 font-medium text-custom-primary-100", { className={cn("mention rounded bg-custom-primary-100/20 px-1 py-0.5 font-medium text-custom-primary-100", {
"bg-yellow-500/20 text-yellow-500": highlightsState "bg-yellow-500/20 text-yellow-500": highlightsState
? highlightsState.includes(props.node.attrs.entity_identifier) ? highlightsState.includes(props.node.attrs.entity_identifier)
: false, : false,
"cursor-pointer": !props.extension.options.readonly, "cursor-pointer": !props.extension.options.readonly,
})} })}
onClick={handleClick}
> >
@{props.node.attrs.label} @{props.node.attrs.label}
</span> </a>
</NodeViewWrapper> </NodeViewWrapper>
); );
}; };

View file

@ -1,41 +1,55 @@
/* eslint-disable @typescript-eslint/no-unused-vars */ import { useCallback, useEffect, useState } from "react";
import { useState } from "react";
//TODO: remove temp flag isActive later and use showAlert as the source of truth //TODO: remove temp flag isActive later and use showAlert as the source of truth
const useReloadConfirmations = (isActive = true) => { const useReloadConfirmations = (isActive = true) => {
const [showAlert, setShowAlert] = useState(false); const [showAlert, setShowAlert] = useState(false);
// const router = useAppRouter();
// const handleBeforeUnload = useCallback( const handleBeforeUnload = useCallback(
// (event: BeforeUnloadEvent) => { (event: BeforeUnloadEvent) => {
// if (!isActive || !showAlert) return; if (!isActive || !showAlert) return;
// event.preventDefault(); event.preventDefault();
// event.returnValue = ""; event.returnValue = "";
// }, },
// [isActive, showAlert] [isActive, showAlert]
// ); );
// const handleRouteChangeStart = useCallback( const handleAnchorClick = useCallback(
// (url: string, { shallow }: { shallow: boolean }) => { (event: MouseEvent) => {
// if (!isActive || !showAlert) return; if (!isActive || !showAlert) return;
// const leave = confirm("Are you sure you want to leave? Changes you made may not be saved."); // Skip if event target is not available or defaultPrevented
// if (!leave) { if (!event.target || event.defaultPrevented) return;
// router.events.emit("routeChangeError", new Error("Route change cancelled by user"), url, shallow); // Skip control/command/option/alt+click
// throw "routeChange aborted."; 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;
// [isActive, router.events, showAlert] 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 leave = confirm("Are you sure you want to leave? Changes you made may not be saved.");
if (!leave) {
event.preventDefault();
event.stopPropagation();
}
},
[isActive, showAlert]
);
// useEffect(() => { useEffect(() => {
// window.addEventListener("beforeunload", handleBeforeUnload); // handle browser refresh
// router.events.on("routeChangeStart", handleRouteChangeStart); window.addEventListener("beforeunload", handleBeforeUnload, true);
// handle anchor tag click
window.addEventListener("click", handleAnchorClick, true);
// TODO: handle back / forward button click
// return () => { return () => {
// window.removeEventListener("beforeunload", handleBeforeUnload); // cleanup
// router.events.off("routeChangeStart", handleRouteChangeStart); window.removeEventListener("beforeunload", handleBeforeUnload, true);
// }; window.removeEventListener("click", handleAnchorClick, true);
// }, [handleBeforeUnload, handleRouteChangeStart, router.events]); };
}, [handleAnchorClick, handleBeforeUnload]);
return { setShowAlert }; return { setShowAlert };
}; };