Warn on tab close when create-flow module or wizard edits have not been saved.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+3
@@ -6,6 +6,7 @@ import {
|
||||
useTranslation,
|
||||
} from "../../../../contexts/MessagesContext";
|
||||
import { useAsyncConfirm } from "../../../../hooks/useAsyncConfirm";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import type { CustomMethodCardFieldBlock } from "../../../../../lib/create/customMethodCardFieldBlocks";
|
||||
import {
|
||||
CUSTOM_METHOD_CARD_WIZARD_MAX_DESCRIPTION_CHARS,
|
||||
@@ -213,6 +214,8 @@ const CustomMethodCardWizardContainer = memo<CustomMethodCardWizardProps>(
|
||||
policyTitle,
|
||||
]);
|
||||
|
||||
useBeforeUnloadGuard(isOpen && isWizardSessionDirty());
|
||||
|
||||
const confirmAbandonWizardEdits = useCallback(async () => {
|
||||
if (!isWizardSessionDirty()) {
|
||||
return true;
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
import CustomMethodCardModalBody from "./CustomMethodCardModalBody";
|
||||
import { buildCustomRuleModalKebabMenu } from "./customRuleModalKebabMenu";
|
||||
import { useDiscardCustomizeConfirm } from "../hooks/useDiscardCustomizeConfirm";
|
||||
import { useBeforeUnloadGuard } from "../../../hooks/useBeforeUnloadGuard";
|
||||
import {
|
||||
communicationPresetFor,
|
||||
conflictManagementPresetFor,
|
||||
@@ -370,6 +371,12 @@ export function FinalReviewChipEditModal({
|
||||
draftFieldBlocks,
|
||||
]);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
isOpen &&
|
||||
!addCustomWizardOpen &&
|
||||
(!coreCustomizeSaveDisabled || !methodCustomizeSaveDisabled),
|
||||
);
|
||||
|
||||
const modalUsesWizardFieldBlocksBody = Boolean(
|
||||
target &&
|
||||
(usesWizardFieldBlocksModalBody({
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useBeforeUnloadGuard } from "../../../hooks/useBeforeUnloadGuard";
|
||||
import Create from "../../../components/modals/Create";
|
||||
import TextInput from "../../../components/controls/TextInput";
|
||||
import ContentLockup from "../../../components/type/ContentLockup";
|
||||
@@ -57,6 +58,8 @@ export function FinalReviewCommunityContextEditModal({
|
||||
[draft],
|
||||
);
|
||||
|
||||
useBeforeUnloadGuard(isOpen && isDirty);
|
||||
|
||||
const characterHint = tField("characterCountTemplate")
|
||||
.replace("{current}", String(draft.length))
|
||||
.replace("{max}", String(COMMUNITY_CONTEXT_FIELD_MAX_LENGTH));
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useState, useCallback, useMemo, useRef } from "react";
|
||||
import { useMessages } from "../../../../contexts/MessagesContext";
|
||||
import { useCreateFlow } from "../../context/CreateFlowContext";
|
||||
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import { useDiscardCustomizeConfirm } from "../../hooks/useDiscardCustomizeConfirm";
|
||||
import { useMethodCardDeckOrdering } from "../../hooks/useMethodCardDeckOrdering";
|
||||
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
|
||||
@@ -57,6 +58,7 @@ import { buildMethodCardWizardInitialValues } from "../../../../../lib/create/me
|
||||
import type { MethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
||||
import {
|
||||
captureMethodCardCustomizeSnapshot,
|
||||
isMethodCardCustomizeUnloadBlocked,
|
||||
type MethodCardCustomizeSnapshot,
|
||||
type MethodCardHeaderDraft,
|
||||
} from "../../../../../lib/create/methodCardCustomizeSession";
|
||||
@@ -88,6 +90,16 @@ export function CommunicationMethodsScreen() {
|
||||
CustomMethodCardFieldBlock[] | null
|
||||
>(null);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
isMethodCardCustomizeUnloadBlocked(
|
||||
createModalOpen,
|
||||
customizeSnapshotRef.current,
|
||||
pendingDraft,
|
||||
draftFieldBlocks,
|
||||
customizeSnapshotRef.current?.headerDraft ?? null,
|
||||
),
|
||||
);
|
||||
|
||||
const selectedIds = state.selectedCommunicationMethodIds ?? [];
|
||||
|
||||
const mergedMethods = useMemo(
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useState, useCallback, useMemo, useRef } from "react";
|
||||
import { useMessages } from "../../../../contexts/MessagesContext";
|
||||
import { useCreateFlow } from "../../context/CreateFlowContext";
|
||||
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import { useDiscardCustomizeConfirm } from "../../hooks/useDiscardCustomizeConfirm";
|
||||
import { useMethodCardDeckOrdering } from "../../hooks/useMethodCardDeckOrdering";
|
||||
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
|
||||
@@ -54,6 +55,7 @@ import { buildMethodCardWizardInitialValues } from "../../../../../lib/create/me
|
||||
import type { MethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
||||
import {
|
||||
captureMethodCardCustomizeSnapshot,
|
||||
isMethodCardCustomizeUnloadBlocked,
|
||||
type MethodCardCustomizeSnapshot,
|
||||
type MethodCardHeaderDraft,
|
||||
} from "../../../../../lib/create/methodCardCustomizeSession";
|
||||
@@ -85,6 +87,16 @@ export function ConflictManagementScreen() {
|
||||
CustomMethodCardFieldBlock[] | null
|
||||
>(null);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
isMethodCardCustomizeUnloadBlocked(
|
||||
createModalOpen,
|
||||
customizeSnapshotRef.current,
|
||||
pendingDraft,
|
||||
draftFieldBlocks,
|
||||
customizeSnapshotRef.current?.headerDraft ?? null,
|
||||
),
|
||||
);
|
||||
|
||||
const selectedIds = state.selectedConflictManagementIds ?? [];
|
||||
|
||||
const mergedMethods = useMemo(
|
||||
|
||||
@@ -17,6 +17,7 @@ import { useState, useCallback, useMemo, useRef } from "react";
|
||||
import { useMessages } from "../../../../contexts/MessagesContext";
|
||||
import { useCreateFlow } from "../../context/CreateFlowContext";
|
||||
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import { useDiscardCustomizeConfirm } from "../../hooks/useDiscardCustomizeConfirm";
|
||||
import { useMethodCardDeckOrdering } from "../../hooks/useMethodCardDeckOrdering";
|
||||
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
|
||||
@@ -55,6 +56,7 @@ import { buildMethodCardWizardInitialValues } from "../../../../../lib/create/me
|
||||
import type { MethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
||||
import {
|
||||
captureMethodCardCustomizeSnapshot,
|
||||
isMethodCardCustomizeUnloadBlocked,
|
||||
type MethodCardCustomizeSnapshot,
|
||||
type MethodCardHeaderDraft,
|
||||
} from "../../../../../lib/create/methodCardCustomizeSession";
|
||||
@@ -86,6 +88,16 @@ export function MembershipMethodsScreen() {
|
||||
CustomMethodCardFieldBlock[] | null
|
||||
>(null);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
isMethodCardCustomizeUnloadBlocked(
|
||||
createModalOpen,
|
||||
customizeSnapshotRef.current,
|
||||
pendingDraft,
|
||||
draftFieldBlocks,
|
||||
customizeSnapshotRef.current?.headerDraft ?? null,
|
||||
),
|
||||
);
|
||||
|
||||
const selectedIds = state.selectedMembershipMethodIds ?? [];
|
||||
|
||||
const mergedMethods = useMemo(
|
||||
|
||||
@@ -26,6 +26,7 @@ import type { InfoMessageBoxItem } from "../../../../components/controls/InfoMes
|
||||
import { useMessages } from "../../../../contexts/MessagesContext";
|
||||
import { useCreateFlow } from "../../context/CreateFlowContext";
|
||||
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import { useDiscardCustomizeConfirm } from "../../hooks/useDiscardCustomizeConfirm";
|
||||
import { useMethodCardDeckOrdering } from "../../hooks/useMethodCardDeckOrdering";
|
||||
import { CreateFlowTwoColumnSelectShell } from "../../components/CreateFlowTwoColumnSelectShell";
|
||||
@@ -60,6 +61,7 @@ import { buildMethodCardWizardInitialValues } from "../../../../../lib/create/me
|
||||
import type { MethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
||||
import {
|
||||
captureMethodCardCustomizeSnapshot,
|
||||
isMethodCardCustomizeUnloadBlocked,
|
||||
type MethodCardCustomizeSnapshot,
|
||||
type MethodCardHeaderDraft,
|
||||
} from "../../../../../lib/create/methodCardCustomizeSession";
|
||||
@@ -91,6 +93,16 @@ export function DecisionApproachesScreen() {
|
||||
CustomMethodCardFieldBlock[] | null
|
||||
>(null);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
isMethodCardCustomizeUnloadBlocked(
|
||||
createModalOpen,
|
||||
customizeSnapshotRef.current,
|
||||
pendingDraft,
|
||||
draftFieldBlocks,
|
||||
customizeSnapshotRef.current?.headerDraft ?? null,
|
||||
),
|
||||
);
|
||||
|
||||
const selectedIds = state.selectedDecisionApproachIds ?? [];
|
||||
const messageBoxCheckedIds = decisionApproachKeyResourceCheckboxIds({
|
||||
detailsById: state.decisionApproachDetailsById,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useMessages } from "../../../../contexts/MessagesContext";
|
||||
import { buildCoreValueChipOptionsFromDraft } from "../../../../../lib/create/coreValueChipOptionsFromDraft";
|
||||
import { useCreateFlow } from "../../context/CreateFlowContext";
|
||||
import { useAsyncConfirm } from "../../../../hooks/useAsyncConfirm";
|
||||
import { useBeforeUnloadGuard } from "../../../../hooks/useBeforeUnloadGuard";
|
||||
import type {
|
||||
CommunityStructureChipSnapshotRow,
|
||||
CoreValueDetailEntry,
|
||||
@@ -257,6 +258,14 @@ export function CoreValuesSelectScreen() {
|
||||
});
|
||||
}, [cv.detailModal, draft, modalSession, requestConfirm]);
|
||||
|
||||
useBeforeUnloadGuard(
|
||||
activeModalChipId != null &&
|
||||
!addCustomWizardOpen &&
|
||||
initialDraftRef.current != null &&
|
||||
(draft.meaning !== initialDraftRef.current.meaning ||
|
||||
draft.signals !== initialDraftRef.current.signals),
|
||||
);
|
||||
|
||||
const handleDuplicateCoreChip = useCallback(() => {
|
||||
if (!activeModalChipId || !modalSession) return;
|
||||
markCreateFlowInteraction();
|
||||
|
||||
Reference in New Issue
Block a user