Seeded section text should look like the form default state, not locked primary, and Customize stays on the kebab instead of unlocking the body. Co-authored-by: Cursor <cursoragent@cursor.com>
784 lines
26 KiB
TypeScript
784 lines
26 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* `conflict-management` step — Figma compact card stack (node `20879-15979`).
|
|
* Registry: `CREATE_FLOW_SCREEN_REGISTRY["conflict-management"]`.
|
|
*
|
|
* Card click opens the Figma "Add Approach" create modal (node `20874-172292`)
|
|
* with four controls rendered by {@link ConflictManagementEditFields}: Core
|
|
* Principle, Applicable Scope (text area), Process Protocol, and Restoration
|
|
* & Fallbacks. The same field set is reused on `/create/final-review` — see
|
|
* `FinalReviewChipEditModal`. Confirm persists both the chip selection and
|
|
* any user edits as a `conflictManagementDetailsById[id]` override.
|
|
*/
|
|
|
|
import { useState, useCallback, useMemo, useRef } from "react";
|
|
import { useMessages } from "../../../../contexts/MessagesContext";
|
|
import { useCreateFlow } from "../../context/CreateFlowContext";
|
|
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
|
|
import { useDiscardCustomizeConfirm } from "../../hooks/useDiscardCustomizeConfirm";
|
|
import { useMethodCardDeckOrdering } from "../../hooks/useMethodCardDeckOrdering";
|
|
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
|
|
import CardStack from "../../../../components/cards/CardStack";
|
|
import Create from "../../../../components/modals/Create";
|
|
import InlineTextButton from "../../../../components/buttons/InlineTextButton";
|
|
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
|
|
import {
|
|
CREATE_FLOW_CARD_STACK_AREA_MAX_CLASS,
|
|
CREATE_FLOW_MD_CENTERED_SHELL_CLASS,
|
|
CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS,
|
|
} from "../../components/createFlowLayoutTokens";
|
|
import { ConflictManagementEditFields } from "../../components/methodEditFields";
|
|
import CustomMethodCardWizard from "../../components/CustomMethodCardWizard";
|
|
import { uploadCreateFlowFile } from "../../../../../lib/create/uploadToServer";
|
|
import { conflictManagementPresetFor } from "../../../../../lib/create/finalReviewChipPresets";
|
|
import type { CustomMethodCardFieldBlock } from "../../../../../lib/create/customMethodCardFieldBlocks";
|
|
import { mergePresetMethodsWithCustom } from "../../../../../lib/create/mergePresetMethodsWithCustom";
|
|
import { moveFacetSelectionIdToFront } from "../../../../../lib/create/methodCardSelectionOrder";
|
|
import { isCustomMethodCardId } from "../../../../../lib/create/isCustomMethodCardId";
|
|
import { conflictManagementFacetMatchesPreset } from "../../../../../lib/create/methodCardFacetMatchesPresetForId";
|
|
import { usesWizardFieldBlocksModalBody } from "../../../../../lib/create/usesWizardFieldBlocksModalBody";
|
|
import { removeMethodCardFromFacetSelection } from "../../../../../lib/create/removeMethodCardFromFacetSelection";
|
|
import {
|
|
cloneMethodCardBlocksForDuplicate,
|
|
cloneMethodCardDetailsForDuplicate,
|
|
duplicateMethodCardTitle,
|
|
forkMethodCardFacetMapsForDuplicate,
|
|
omitIdFromStringRecord,
|
|
} from "../../../../../lib/create/duplicateMethodCardModalDraft";
|
|
import type { ConflictManagementDetailEntry } from "../../types";
|
|
import CustomMethodCardModalBody from "../../components/CustomMethodCardModalBody";
|
|
import { buildCustomRuleModalKebabMenu } from "../../components/customRuleModalKebabMenu";
|
|
import { methodCardMetaWithCustomizeHeader } from "../../../../../lib/create/methodCardCustomizeMetaPatch";
|
|
import { buildMethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
|
import type { MethodCardWizardInitialValues } from "../../../../../lib/create/methodCardWizardPrefill";
|
|
import {
|
|
captureMethodCardCustomizeSnapshot,
|
|
type MethodCardCustomizeSnapshot,
|
|
type MethodCardHeaderDraft,
|
|
} from "../../../../../lib/create/methodCardCustomizeSession";
|
|
|
|
export function ConflictManagementScreen() {
|
|
const m = useMessages();
|
|
const cm = m.create.customRule.conflictManagement;
|
|
const modalKebabMenu = m.create.customRule.modalKebabMenu;
|
|
const mdUp = useCreateFlowMdUp();
|
|
const { confirmDiscard, confirmDialog } = useDiscardCustomizeConfirm();
|
|
const { state, updateState, replaceState, markCreateFlowInteraction } =
|
|
useCreateFlow();
|
|
const pendingEphemeralDuplicateIdRef = useRef<string | null>(null);
|
|
const customizeSnapshotRef = useRef<
|
|
MethodCardCustomizeSnapshot<ConflictManagementDetailEntry> | null
|
|
>(null);
|
|
const [expanded, setExpanded] = useState(false);
|
|
const [createModalOpen, setCreateModalOpen] = useState(false);
|
|
const [pendingCardId, setPendingCardId] = useState<string | null>(null);
|
|
const [pendingDraft, setPendingDraft] =
|
|
useState<ConflictManagementDetailEntry | null>(null);
|
|
const [addCustomWizardOpen, setAddCustomWizardOpen] = useState(false);
|
|
const [wizardCustomizeCardId, setWizardCustomizeCardId] = useState<
|
|
string | null
|
|
>(null);
|
|
const [wizardInitialValues, setWizardInitialValues] =
|
|
useState<MethodCardWizardInitialValues | null>(null);
|
|
const [draftFieldBlocks, setDraftFieldBlocks] = useState<
|
|
CustomMethodCardFieldBlock[] | null
|
|
>(null);
|
|
|
|
const selectedIds = state.selectedConflictManagementIds ?? [];
|
|
|
|
const mergedMethods = useMemo(
|
|
() =>
|
|
mergePresetMethodsWithCustom(
|
|
cm.methods,
|
|
selectedIds,
|
|
state.customMethodCardMetaById,
|
|
),
|
|
[cm.methods, selectedIds, state.customMethodCardMetaById],
|
|
);
|
|
|
|
const { sampleCards, compactCardIds, methodById, recommendationsReady } =
|
|
useMethodCardDeckOrdering(
|
|
"conflictManagement",
|
|
mergedMethods,
|
|
selectedIds,
|
|
);
|
|
|
|
const handleOpenAddWizard = useCallback(() => {
|
|
markCreateFlowInteraction();
|
|
setWizardCustomizeCardId(null);
|
|
setWizardInitialValues(null);
|
|
setAddCustomWizardOpen(true);
|
|
}, [markCreateFlowInteraction]);
|
|
|
|
const title = expanded ? cm.page.expandedTitle : cm.page.compactTitle;
|
|
|
|
const description = expanded ? (
|
|
<>
|
|
{cm.page.expandedDescriptionBefore}
|
|
<InlineTextButton onClick={handleOpenAddWizard}>
|
|
{cm.page.compactDescriptionLinkLabel}
|
|
</InlineTextButton>
|
|
{cm.page.expandedDescriptionAfter}
|
|
</>
|
|
) : (
|
|
<>
|
|
{cm.page.compactDescriptionBefore}
|
|
<InlineTextButton onClick={handleOpenAddWizard}>
|
|
{cm.page.compactDescriptionLinkLabel}
|
|
</InlineTextButton>
|
|
{cm.page.compactDescriptionAfter}
|
|
</>
|
|
);
|
|
|
|
const seedDraft = useCallback(
|
|
(id: string): ConflictManagementDetailEntry => {
|
|
const saved = state.conflictManagementDetailsById?.[id];
|
|
if (saved) {
|
|
return {
|
|
...saved,
|
|
applicableScope: [...saved.applicableScope],
|
|
selectedApplicableScope: [...saved.selectedApplicableScope],
|
|
};
|
|
}
|
|
return conflictManagementPresetFor(id);
|
|
},
|
|
[state.conflictManagementDetailsById],
|
|
);
|
|
|
|
const handleCardClick = useCallback(
|
|
(id: string) => {
|
|
markCreateFlowInteraction();
|
|
const draft = seedDraft(id);
|
|
const persistedBlocks = state.customMethodCardFieldBlocksById?.[id];
|
|
const initialBlocks =
|
|
Array.isArray(persistedBlocks) && persistedBlocks.length > 0
|
|
? structuredClone(persistedBlocks)
|
|
: null;
|
|
const method = methodById.get(id);
|
|
const meta = state.customMethodCardMetaById?.[id];
|
|
const headerDraft: MethodCardHeaderDraft = {
|
|
title: meta?.label ?? method?.label ?? cm.confirmModal.title,
|
|
description:
|
|
meta?.supportText ??
|
|
method?.supportText ??
|
|
cm.confirmModal.description,
|
|
};
|
|
customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
|
|
draft,
|
|
initialBlocks,
|
|
headerDraft,
|
|
);
|
|
setPendingCardId(id);
|
|
setPendingDraft(draft);
|
|
setDraftFieldBlocks(initialBlocks);
|
|
setCreateModalOpen(true);
|
|
},
|
|
[
|
|
cm.confirmModal.description,
|
|
cm.confirmModal.title,
|
|
markCreateFlowInteraction,
|
|
methodById,
|
|
seedDraft,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
],
|
|
);
|
|
|
|
const handleDraftChange = useCallback(
|
|
(next: ConflictManagementDetailEntry) => {
|
|
markCreateFlowInteraction();
|
|
setPendingDraft(next);
|
|
},
|
|
[markCreateFlowInteraction],
|
|
);
|
|
|
|
const isSelectedCardModal =
|
|
pendingCardId !== null && selectedIds.includes(pendingCardId);
|
|
const showMethodModalPrimary = true;
|
|
|
|
const customFacetDetailsMatchPreset = useMemo(() => {
|
|
if (!pendingCardId || !pendingDraft) return false;
|
|
if (!isCustomMethodCardId(pendingCardId, state.customMethodCardMetaById)) {
|
|
return false;
|
|
}
|
|
return conflictManagementFacetMatchesPreset(pendingDraft, pendingCardId);
|
|
}, [
|
|
pendingCardId,
|
|
pendingDraft,
|
|
state.customMethodCardMetaById,
|
|
]);
|
|
|
|
const modalUsesWizardFieldBlocksBody = useMemo(
|
|
() =>
|
|
Boolean(
|
|
pendingCardId &&
|
|
usesWizardFieldBlocksModalBody({
|
|
methodId: pendingCardId,
|
|
meta: state.customMethodCardMetaById,
|
|
fieldBlocksById: state.customMethodCardFieldBlocksById,
|
|
modalEditUnlocked: true,
|
|
draftFieldBlocks,
|
|
customFacetDetailsMatchPreset,
|
|
}),
|
|
),
|
|
[
|
|
customFacetDetailsMatchPreset,
|
|
draftFieldBlocks,
|
|
pendingCardId,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
],
|
|
);
|
|
|
|
const handleCreateModalClose = useCallback(async () => {
|
|
if (
|
|
!(await confirmDiscard(
|
|
true,
|
|
customizeSnapshotRef.current,
|
|
pendingDraft,
|
|
draftFieldBlocks,
|
|
customizeSnapshotRef.current?.headerDraft ?? null,
|
|
))
|
|
) {
|
|
return;
|
|
}
|
|
customizeSnapshotRef.current = null;
|
|
const ephemeralId = pendingEphemeralDuplicateIdRef.current;
|
|
if (ephemeralId) {
|
|
pendingEphemeralDuplicateIdRef.current = null;
|
|
replaceState((prev) => ({
|
|
...prev,
|
|
customMethodCardMetaById: omitIdFromStringRecord(
|
|
prev.customMethodCardMetaById,
|
|
ephemeralId,
|
|
),
|
|
conflictManagementDetailsById: omitIdFromStringRecord(
|
|
prev.conflictManagementDetailsById,
|
|
ephemeralId,
|
|
),
|
|
customMethodCardFieldBlocksById: omitIdFromStringRecord(
|
|
prev.customMethodCardFieldBlocksById,
|
|
ephemeralId,
|
|
),
|
|
}));
|
|
}
|
|
setCreateModalOpen(false);
|
|
setPendingCardId(null);
|
|
setPendingDraft(null);
|
|
setDraftFieldBlocks(null);
|
|
}, [
|
|
confirmDiscard,
|
|
draftFieldBlocks,
|
|
pendingDraft,
|
|
replaceState,
|
|
]);
|
|
|
|
const handleRemoveSelectedFromModal = useCallback(async () => {
|
|
if (!pendingCardId || !selectedIds.includes(pendingCardId)) {
|
|
return;
|
|
}
|
|
markCreateFlowInteraction();
|
|
if (
|
|
!(await confirmDiscard(
|
|
true,
|
|
customizeSnapshotRef.current,
|
|
pendingDraft,
|
|
draftFieldBlocks,
|
|
customizeSnapshotRef.current?.headerDraft ?? null,
|
|
))
|
|
) {
|
|
return;
|
|
}
|
|
customizeSnapshotRef.current = null;
|
|
updateState(
|
|
removeMethodCardFromFacetSelection(
|
|
state,
|
|
"conflictManagement",
|
|
pendingCardId,
|
|
),
|
|
);
|
|
await handleCreateModalClose();
|
|
}, [
|
|
confirmDiscard,
|
|
draftFieldBlocks,
|
|
handleCreateModalClose,
|
|
markCreateFlowInteraction,
|
|
pendingDraft,
|
|
pendingCardId,
|
|
selectedIds,
|
|
state,
|
|
updateState,
|
|
]);
|
|
|
|
const handleCustomize = useCallback(() => {
|
|
markCreateFlowInteraction();
|
|
if (!pendingCardId) {
|
|
return;
|
|
}
|
|
const method = methodById.get(pendingCardId);
|
|
setWizardInitialValues(
|
|
buildMethodCardWizardInitialValues({
|
|
cardId: pendingCardId,
|
|
fallbackTitle: method?.label ?? cm.confirmModal.title,
|
|
fallbackDescription:
|
|
method?.supportText ?? cm.confirmModal.description,
|
|
meta: state.customMethodCardMetaById,
|
|
persistedBlocks: state.customMethodCardFieldBlocksById,
|
|
draftFieldBlocks,
|
|
facetPrefill: pendingDraft
|
|
? {
|
|
group: "conflictManagement",
|
|
draft: pendingDraft,
|
|
headings: cm.sectionHeadings,
|
|
}
|
|
: undefined,
|
|
}),
|
|
);
|
|
setWizardCustomizeCardId(pendingCardId);
|
|
setCreateModalOpen(false);
|
|
setAddCustomWizardOpen(true);
|
|
}, [
|
|
cm.confirmModal.description,
|
|
cm.confirmModal.title,
|
|
cm.sectionHeadings,
|
|
draftFieldBlocks,
|
|
markCreateFlowInteraction,
|
|
methodById,
|
|
pendingCardId,
|
|
pendingDraft,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
]);
|
|
|
|
const handleDuplicateCustomCard = useCallback(() => {
|
|
if (
|
|
!pendingCardId ||
|
|
!isCustomMethodCardId(pendingCardId, state.customMethodCardMetaById)
|
|
) {
|
|
return;
|
|
}
|
|
markCreateFlowInteraction();
|
|
const newId = crypto.randomUUID();
|
|
const meta = state.customMethodCardMetaById![pendingCardId]!;
|
|
const detailsClone = cloneMethodCardDetailsForDuplicate(
|
|
pendingDraft,
|
|
state.conflictManagementDetailsById?.[pendingCardId],
|
|
() => conflictManagementPresetFor(newId),
|
|
);
|
|
const blocksClone = structuredClone(
|
|
draftFieldBlocks !== null
|
|
? draftFieldBlocks
|
|
: cloneMethodCardBlocksForDuplicate(
|
|
state.customMethodCardFieldBlocksById,
|
|
pendingCardId,
|
|
),
|
|
);
|
|
const suffix = modalKebabMenu.duplicateTitleSuffix;
|
|
const priorEphemeral = pendingEphemeralDuplicateIdRef.current;
|
|
const maps = forkMethodCardFacetMapsForDuplicate({
|
|
customMethodCardMetaById: state.customMethodCardMetaById,
|
|
facetDetailsById: state.conflictManagementDetailsById,
|
|
customMethodCardFieldBlocksById: state.customMethodCardFieldBlocksById,
|
|
omitId: priorEphemeral,
|
|
});
|
|
maps.customMethodCardMetaById[newId] = {
|
|
label: duplicateMethodCardTitle(meta.label, suffix),
|
|
supportText: meta.supportText,
|
|
};
|
|
maps.facetDetailsById[newId] = detailsClone;
|
|
maps.customMethodCardFieldBlocksById[newId] = blocksClone;
|
|
updateState({
|
|
customMethodCardMetaById: maps.customMethodCardMetaById,
|
|
conflictManagementDetailsById: maps.facetDetailsById,
|
|
customMethodCardFieldBlocksById: maps.customMethodCardFieldBlocksById,
|
|
});
|
|
pendingEphemeralDuplicateIdRef.current = newId;
|
|
customizeSnapshotRef.current = null;
|
|
setPendingCardId(newId);
|
|
setPendingDraft(structuredClone(detailsClone));
|
|
setDraftFieldBlocks(
|
|
blocksClone.length > 0 ? structuredClone(blocksClone) : null,
|
|
);
|
|
}, [
|
|
draftFieldBlocks,
|
|
markCreateFlowInteraction,
|
|
modalKebabMenu.duplicateTitleSuffix,
|
|
pendingCardId,
|
|
pendingDraft,
|
|
state.conflictManagementDetailsById,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
updateState,
|
|
]);
|
|
|
|
const handleDuplicatePrefabCard = useCallback(() => {
|
|
if (
|
|
!pendingCardId ||
|
|
isCustomMethodCardId(pendingCardId, state.customMethodCardMetaById)
|
|
) {
|
|
return;
|
|
}
|
|
const method = methodById.get(pendingCardId);
|
|
if (!method || !pendingDraft) {
|
|
return;
|
|
}
|
|
markCreateFlowInteraction();
|
|
const newId = crypto.randomUUID();
|
|
const detailsClone = cloneMethodCardDetailsForDuplicate(
|
|
pendingDraft,
|
|
state.conflictManagementDetailsById?.[pendingCardId],
|
|
() => conflictManagementPresetFor(newId),
|
|
);
|
|
const blocksClone = structuredClone(
|
|
draftFieldBlocks !== null
|
|
? draftFieldBlocks
|
|
: cloneMethodCardBlocksForDuplicate(
|
|
state.customMethodCardFieldBlocksById,
|
|
pendingCardId,
|
|
),
|
|
);
|
|
const suffix = modalKebabMenu.duplicateTitleSuffix;
|
|
const priorEphemeral = pendingEphemeralDuplicateIdRef.current;
|
|
const maps = forkMethodCardFacetMapsForDuplicate({
|
|
customMethodCardMetaById: state.customMethodCardMetaById,
|
|
facetDetailsById: state.conflictManagementDetailsById,
|
|
customMethodCardFieldBlocksById: state.customMethodCardFieldBlocksById,
|
|
omitId: priorEphemeral,
|
|
});
|
|
maps.customMethodCardMetaById[newId] = {
|
|
label: duplicateMethodCardTitle(method.label, suffix),
|
|
supportText: method.supportText,
|
|
};
|
|
maps.facetDetailsById[newId] = detailsClone;
|
|
maps.customMethodCardFieldBlocksById[newId] = blocksClone;
|
|
updateState({
|
|
customMethodCardMetaById: maps.customMethodCardMetaById,
|
|
conflictManagementDetailsById: maps.facetDetailsById,
|
|
customMethodCardFieldBlocksById: maps.customMethodCardFieldBlocksById,
|
|
});
|
|
pendingEphemeralDuplicateIdRef.current = newId;
|
|
customizeSnapshotRef.current = null;
|
|
setPendingCardId(newId);
|
|
setPendingDraft(structuredClone(detailsClone));
|
|
setDraftFieldBlocks(
|
|
blocksClone.length > 0 ? structuredClone(blocksClone) : null,
|
|
);
|
|
}, [
|
|
draftFieldBlocks,
|
|
markCreateFlowInteraction,
|
|
methodById,
|
|
modalKebabMenu.duplicateTitleSuffix,
|
|
pendingCardId,
|
|
pendingDraft,
|
|
state.conflictManagementDetailsById,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
updateState,
|
|
]);
|
|
|
|
const kebabMenuItems = useMemo(
|
|
() =>
|
|
buildCustomRuleModalKebabMenu(modalKebabMenu, {
|
|
showCustomize: true,
|
|
onCustomize: handleCustomize,
|
|
onDuplicate:
|
|
(state.editingPublishedRuleId?.trim() ?? "") !== "" || !pendingCardId
|
|
? undefined
|
|
: isCustomMethodCardId(
|
|
pendingCardId,
|
|
state.customMethodCardMetaById,
|
|
)
|
|
? handleDuplicateCustomCard
|
|
: handleDuplicatePrefabCard,
|
|
showRemove: isSelectedCardModal,
|
|
onRemove: handleRemoveSelectedFromModal,
|
|
}),
|
|
[
|
|
handleCustomize,
|
|
handleDuplicateCustomCard,
|
|
handleDuplicatePrefabCard,
|
|
handleRemoveSelectedFromModal,
|
|
isSelectedCardModal,
|
|
modalKebabMenu,
|
|
pendingCardId,
|
|
state.customMethodCardMetaById,
|
|
state.editingPublishedRuleId,
|
|
],
|
|
);
|
|
|
|
const modalConfig = pendingCardId
|
|
? (() => {
|
|
const method = methodById.get(pendingCardId);
|
|
const meta = state.customMethodCardMetaById?.[pendingCardId];
|
|
const saveLabel = modalKebabMenu.saveEdits;
|
|
return {
|
|
title: meta?.label ?? method?.label ?? cm.confirmModal.title,
|
|
description:
|
|
meta?.supportText ??
|
|
method?.supportText ??
|
|
cm.confirmModal.description,
|
|
nextButtonText: isSelectedCardModal
|
|
? saveLabel
|
|
: cm.addApproach.nextButtonText,
|
|
};
|
|
})()
|
|
: {
|
|
title: cm.confirmModal.title,
|
|
description: cm.confirmModal.description,
|
|
nextButtonText: cm.confirmModal.nextButtonText,
|
|
};
|
|
|
|
const handleCloseAddWizard = useCallback(() => {
|
|
const resumeCardId = wizardCustomizeCardId;
|
|
setAddCustomWizardOpen(false);
|
|
setWizardCustomizeCardId(null);
|
|
setWizardInitialValues(null);
|
|
if (resumeCardId && pendingCardId === resumeCardId) {
|
|
setCreateModalOpen(true);
|
|
}
|
|
}, [pendingCardId, wizardCustomizeCardId]);
|
|
|
|
const handleFinalizeCustomCard = useCallback(
|
|
({
|
|
title,
|
|
description,
|
|
fieldBlocks,
|
|
}: {
|
|
title: string;
|
|
description: string;
|
|
fieldBlocks: CustomMethodCardFieldBlock[];
|
|
}) => {
|
|
markCreateFlowInteraction();
|
|
const existingId = wizardCustomizeCardId;
|
|
if (existingId) {
|
|
updateState({
|
|
selectedConflictManagementIds: moveFacetSelectionIdToFront(
|
|
selectedIds,
|
|
existingId,
|
|
),
|
|
customMethodCardMetaById: methodCardMetaWithCustomizeHeader(
|
|
state.customMethodCardMetaById,
|
|
existingId,
|
|
{ title, description },
|
|
),
|
|
...(pendingDraft
|
|
? {
|
|
conflictManagementDetailsById: {
|
|
...(state.conflictManagementDetailsById ?? {}),
|
|
[existingId]: pendingDraft,
|
|
},
|
|
}
|
|
: {}),
|
|
customMethodCardFieldBlocksById: {
|
|
...(state.customMethodCardFieldBlocksById ?? {}),
|
|
[existingId]: fieldBlocks,
|
|
},
|
|
});
|
|
if (pendingDraft) {
|
|
customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
|
|
pendingDraft,
|
|
fieldBlocks,
|
|
{ title, description },
|
|
);
|
|
}
|
|
setDraftFieldBlocks(structuredClone(fieldBlocks));
|
|
setAddCustomWizardOpen(false);
|
|
return;
|
|
}
|
|
const id = crypto.randomUUID();
|
|
updateState({
|
|
selectedConflictManagementIds: moveFacetSelectionIdToFront(
|
|
selectedIds,
|
|
id,
|
|
),
|
|
customMethodCardMetaById: {
|
|
...(state.customMethodCardMetaById ?? {}),
|
|
[id]: { label: title, supportText: description },
|
|
},
|
|
conflictManagementDetailsById: {
|
|
...(state.conflictManagementDetailsById ?? {}),
|
|
[id]: conflictManagementPresetFor(id),
|
|
},
|
|
customMethodCardFieldBlocksById: {
|
|
...(state.customMethodCardFieldBlocksById ?? {}),
|
|
[id]: fieldBlocks,
|
|
},
|
|
});
|
|
},
|
|
[
|
|
markCreateFlowInteraction,
|
|
pendingDraft,
|
|
selectedIds,
|
|
state.conflictManagementDetailsById,
|
|
state.customMethodCardFieldBlocksById,
|
|
state.customMethodCardMetaById,
|
|
updateState,
|
|
wizardCustomizeCardId,
|
|
],
|
|
);
|
|
|
|
const handleCreateModalPrimary = useCallback(() => {
|
|
if (!pendingCardId) {
|
|
void handleCreateModalClose();
|
|
return;
|
|
}
|
|
markCreateFlowInteraction();
|
|
|
|
const persistWizardBlocks =
|
|
modalUsesWizardFieldBlocksBody && draftFieldBlocks !== null;
|
|
|
|
if (selectedIds.includes(pendingCardId)) {
|
|
if (persistWizardBlocks) {
|
|
updateState({
|
|
customMethodCardFieldBlocksById: {
|
|
...(state.customMethodCardFieldBlocksById ?? {}),
|
|
[pendingCardId]: structuredClone(draftFieldBlocks ?? []),
|
|
},
|
|
});
|
|
} else if (pendingDraft) {
|
|
updateState({
|
|
conflictManagementDetailsById: {
|
|
...(state.conflictManagementDetailsById ?? {}),
|
|
[pendingCardId]: pendingDraft,
|
|
},
|
|
});
|
|
}
|
|
pendingEphemeralDuplicateIdRef.current = null;
|
|
customizeSnapshotRef.current = null;
|
|
void handleCreateModalClose();
|
|
return;
|
|
}
|
|
|
|
if (!pendingDraft) {
|
|
void handleCreateModalClose();
|
|
return;
|
|
}
|
|
updateState({
|
|
selectedConflictManagementIds: moveFacetSelectionIdToFront(
|
|
selectedIds,
|
|
pendingCardId,
|
|
),
|
|
conflictManagementDetailsById: {
|
|
...(state.conflictManagementDetailsById ?? {}),
|
|
[pendingCardId]: pendingDraft,
|
|
},
|
|
...(persistWizardBlocks
|
|
? {
|
|
customMethodCardFieldBlocksById: {
|
|
...(state.customMethodCardFieldBlocksById ?? {}),
|
|
[pendingCardId]: structuredClone(draftFieldBlocks ?? []),
|
|
},
|
|
}
|
|
: {}),
|
|
});
|
|
pendingEphemeralDuplicateIdRef.current = null;
|
|
customizeSnapshotRef.current = null;
|
|
void handleCreateModalClose();
|
|
}, [
|
|
draftFieldBlocks,
|
|
handleCreateModalClose,
|
|
markCreateFlowInteraction,
|
|
modalUsesWizardFieldBlocksBody,
|
|
pendingCardId,
|
|
pendingDraft,
|
|
selectedIds,
|
|
state,
|
|
updateState,
|
|
]);
|
|
|
|
return (
|
|
<>
|
|
<CreateFlowStepShell
|
|
variant="wideGridLoosePadding"
|
|
contentTopBelowMd="space-800"
|
|
className={CREATE_FLOW_MD_CENTERED_SHELL_CLASS}
|
|
>
|
|
<div className="flex w-full min-w-0 flex-col items-center gap-6">
|
|
<div className={CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}>
|
|
<CreateFlowHeaderLockup
|
|
title={title}
|
|
description={description}
|
|
justification="center"
|
|
/>
|
|
</div>
|
|
<div
|
|
className={CREATE_FLOW_CARD_STACK_AREA_MAX_CLASS}
|
|
aria-busy={!recommendationsReady}
|
|
>
|
|
{recommendationsReady && (
|
|
<CardStack
|
|
cards={sampleCards}
|
|
selectedIds={selectedIds}
|
|
onCardSelect={handleCardClick}
|
|
expanded={expanded}
|
|
onToggleExpand={() => {
|
|
markCreateFlowInteraction();
|
|
setExpanded((prev) => !prev);
|
|
}}
|
|
hasMore={true}
|
|
toggleLabel={cm.page.seeAllLink}
|
|
compactRecommendedLimit={5}
|
|
compactCardIds={compactCardIds}
|
|
compactDesktopLayout="pyramidFive"
|
|
headerLockupSize={mdUp ? "L" : "M"}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<Create
|
|
isOpen={createModalOpen}
|
|
onClose={handleCreateModalClose}
|
|
onNext={handleCreateModalPrimary}
|
|
title={modalConfig.title}
|
|
description={modalConfig.description}
|
|
nextButtonText={modalConfig.nextButtonText}
|
|
showBackButton={false}
|
|
showNextButton={showMethodModalPrimary}
|
|
backdropVariant="blurredYellow"
|
|
kebabTriggerAriaLabel={modalKebabMenu.triggerAriaLabel}
|
|
kebabMenuAriaLabel={modalKebabMenu.menuAriaLabel}
|
|
kebabMenuItems={kebabMenuItems}
|
|
>
|
|
{pendingCardId && pendingDraft ? (
|
|
modalUsesWizardFieldBlocksBody ? (
|
|
<CustomMethodCardModalBody
|
|
cardId={pendingCardId}
|
|
blocksById={state.customMethodCardFieldBlocksById}
|
|
blocksOverride={
|
|
draftFieldBlocks !== null ? draftFieldBlocks : undefined
|
|
}
|
|
policyMeta={state.customMethodCardMetaById?.[pendingCardId]}
|
|
showPolicyContentLockupWhenNoBlocks={
|
|
draftFieldBlocks === null || draftFieldBlocks.length === 0
|
|
}
|
|
onFieldBlocksChange={
|
|
draftFieldBlocks === null
|
|
? undefined
|
|
: (next) => setDraftFieldBlocks(next)
|
|
}
|
|
/>
|
|
) : (
|
|
<ConflictManagementEditFields
|
|
value={pendingDraft}
|
|
onChange={handleDraftChange}
|
|
/>
|
|
)
|
|
) : null}
|
|
</Create>
|
|
</CreateFlowStepShell>
|
|
<CustomMethodCardWizard
|
|
isOpen={addCustomWizardOpen}
|
|
onClose={handleCloseAddWizard}
|
|
initialValues={wizardInitialValues}
|
|
onFinalize={handleFinalizeCustomCard}
|
|
onPersistCustomUploadFile={(file) =>
|
|
uploadCreateFlowFile(file, "customMethodAttachment")
|
|
}
|
|
/>
|
|
{confirmDialog}
|
|
</>
|
|
);
|
|
}
|