57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useBeforeUnload, useBlocker } from "react-router-dom";
|
|
|
|
import { Button } from "../components/ui/button.jsx";
|
|
import { Dialog } from "../components/ui/dialog.jsx";
|
|
import { useLocale } from "../i18n/index.js";
|
|
|
|
export function useDirtyNavigationGuard(when: boolean) {
|
|
const blocker = useBlocker(when);
|
|
|
|
useBeforeUnload(
|
|
useCallback(
|
|
(event) => {
|
|
if (!when) return;
|
|
event.preventDefault();
|
|
event.returnValue = "";
|
|
},
|
|
[when],
|
|
),
|
|
{ capture: true },
|
|
);
|
|
|
|
return Object.freeze({
|
|
blocked: blocker.state === "blocked",
|
|
stay() {
|
|
blocker.reset?.();
|
|
},
|
|
leave() {
|
|
blocker.proceed?.();
|
|
},
|
|
});
|
|
}
|
|
|
|
export function DirtyNavigationDialog(props: Readonly<{
|
|
guard: ReturnType<typeof useDirtyNavigationGuard>;
|
|
}>) {
|
|
const { message } = useLocale();
|
|
return (
|
|
<Dialog
|
|
open={props.guard.blocked}
|
|
onClose={props.guard.stay}
|
|
title={message("form.unsaved.title")}
|
|
description={message("form.unsaved.description")}
|
|
actions={
|
|
<>
|
|
<Button variant="secondary" onClick={props.guard.stay}>
|
|
{message("action.continueEditing")}
|
|
</Button>
|
|
<Button variant="danger" onClick={props.guard.leave}>
|
|
{message("action.discardAndLeave")}
|
|
</Button>
|
|
</>
|
|
}
|
|
/>
|
|
);
|
|
}
|