Files
community-rule/app/(app)/create/screens/right-rail/DecisionApproachesScreen.tsx
T
adilalloandCursor 20ea4a2f30 Give MultiSelect chips accessible names and start creation fields empty.
Catalog chips now announce Select or Deselect so they are named for assistive tech. Method and value modals open blank; Generate draft inserts the catalog copy that used to be prefilled, and Customize still keeps the section headings.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-29 15:59:00 -06:00

862 lines
28 KiB
TypeScript

"use client";
/**
* `decision-approaches` step — Figma “Flow — Right Rail” (node `20523-23509`).
* Registry: `CREATE_FLOW_SCREEN_REGISTRY["decision-approaches"]` (`layoutKind: "right-rail"`).
*
* Layout matches {@link CreateFlowTwoColumnSelectShell}: one column below `lg` (1024px), two columns
* at `lg+` with a scrollable rail — same breakpoint and height chain as select steps, distinct content.
*
* Card click opens the Figma "Add Approach" create modal (node `20870-72155`) with five controls
* rendered by {@link DecisionApproachEditFields}: Core Principle, Applicable Scope, Step-by-Step
* Instructions, Consensus Level, and Objections & Deadlocks. The same field set is reused on
* `/create/final-review` — see `FinalReviewChipEditModal`. Confirm persists both the chip
* selection and any user edits as a `decisionApproachDetailsById[id]` override; section
* defaults come from `messages/en/create/customRule/decisionApproaches.json` and will be
* replaced with DB-driven content.
*/
import { useState, useCallback, useMemo, useRef } from "react";
import CardStack from "../../../../components/cards/CardStack";
import HeaderLockup from "../../../../components/type/HeaderLockup";
import Create from "../../../../components/modals/Create";
import InlineTextButton from "../../../../components/buttons/InlineTextButton";
import InfoMessageBox from "../../../../components/controls/InfoMessageBox";
import type { InfoMessageBoxItem } from "../../../../components/controls/InfoMessageBox/InfoMessageBox.types";
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";
import { DecisionApproachEditFields } from "../../components/methodEditFields";
import CustomMethodCardWizard from "../../components/CustomMethodCardWizard";
import { uploadCreateFlowFile } from "../../../../../lib/create/uploadToServer";
import { decisionApproachPresetFor, emptyDecisionApproachTextFields } from "../../../../../lib/create/finalReviewChipPresets";
import {
applyDecisionApproachKeyResources,
decisionApproachKeyResourceCheckboxIds,
selectedKeyResourceLabelsFromCheckedIds,
} from "../../../../../lib/create/decisionApproachKeyResources";
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 { decisionApproachFacetMatchesPreset } 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 { DecisionApproachDetailEntry } 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,
isMethodCardCustomizeUnloadBlocked,
type MethodCardCustomizeSnapshot,
type MethodCardHeaderDraft,
} from "../../../../../lib/create/methodCardCustomizeSession";
export function DecisionApproachesScreen() {
const m = useMessages();
const da = m.create.customRule.decisionApproaches;
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<DecisionApproachDetailEntry> | null
>(null);
const [expanded, setExpanded] = useState(false);
const [createModalOpen, setCreateModalOpen] = useState(false);
const [pendingCardId, setPendingCardId] = useState<string | null>(null);
const [pendingDraft, setPendingDraft] =
useState<DecisionApproachDetailEntry | 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);
useBeforeUnloadGuard(
isMethodCardCustomizeUnloadBlocked(
createModalOpen,
customizeSnapshotRef.current,
pendingDraft,
draftFieldBlocks,
customizeSnapshotRef.current?.headerDraft ?? null,
),
);
const selectedIds = state.selectedDecisionApproachIds ?? [];
const messageBoxCheckedIds = decisionApproachKeyResourceCheckboxIds({
detailsById: state.decisionApproachDetailsById,
selectedApproachIds: selectedIds,
reminderIds: state.selectedDecisionKeyResourceIds,
openDraft: pendingDraft,
});
const messageBoxItems: InfoMessageBoxItem[] = useMemo(
() =>
da.messageBox.items.map((item) => ({
id: item.id,
label: item.label,
})),
[da.messageBox.items],
);
const mergedMethods = useMemo(
() =>
mergePresetMethodsWithCustom(
da.methods,
selectedIds,
state.customMethodCardMetaById,
),
[da.methods, selectedIds, state.customMethodCardMetaById],
);
const { sampleCards, compactCardIds, methodById, recommendationsReady } =
useMethodCardDeckOrdering(
"decisionApproaches",
mergedMethods,
selectedIds,
);
const handleOpenAddWizard = useCallback(() => {
markCreateFlowInteraction();
setWizardCustomizeCardId(null);
setWizardInitialValues(null);
setAddCustomWizardOpen(true);
}, [markCreateFlowInteraction]);
const sidebarDescription = (
<>
{da.sidebar.descriptionBefore}
<InlineTextButton onClick={handleOpenAddWizard}>
{da.sidebar.descriptionLinkLabel}
</InlineTextButton>
{da.sidebar.descriptionAfter}
</>
);
const handleMessageBoxCheckboxChange = useCallback(
(id: string, checked: boolean) => {
markCreateFlowInteraction();
const nextCheckedIds = checked
? [...messageBoxCheckedIds, id]
: messageBoxCheckedIds.filter((x) => x !== id);
const nextLabels =
selectedKeyResourceLabelsFromCheckedIds(nextCheckedIds);
if (pendingDraft) {
setPendingDraft(
applyDecisionApproachKeyResources(pendingDraft, nextLabels),
);
return;
}
updateState({
selectedDecisionKeyResourceIds: nextCheckedIds,
});
},
[
markCreateFlowInteraction,
messageBoxCheckedIds,
pendingDraft,
updateState,
],
);
const seedDraft = useCallback(
(id: string): DecisionApproachDetailEntry => {
const saved = state.decisionApproachDetailsById?.[id];
if (saved) {
return structuredClone(saved);
}
return emptyDecisionApproachTextFields(decisionApproachPresetFor(id));
},
[state.decisionApproachDetailsById],
);
const handleCardSelect = 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 ?? da.confirmModal.title,
description:
meta?.supportText ??
method?.supportText ??
da.confirmModal.description,
};
customizeSnapshotRef.current = captureMethodCardCustomizeSnapshot(
draft,
initialBlocks,
headerDraft,
);
setPendingCardId(id);
setPendingDraft(draft);
setDraftFieldBlocks(initialBlocks);
setCreateModalOpen(true);
},
[
da.confirmModal.description,
da.confirmModal.title,
markCreateFlowInteraction,
methodById,
seedDraft,
state.customMethodCardFieldBlocksById,
state.customMethodCardMetaById,
],
);
const handleDraftChange = useCallback(
(next: DecisionApproachDetailEntry) => {
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 decisionApproachFacetMatchesPreset(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,
),
decisionApproachDetailsById: omitIdFromStringRecord(
prev.decisionApproachDetailsById,
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,
"decisionApproaches",
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 ?? da.confirmModal.title,
fallbackDescription:
method?.supportText ?? da.confirmModal.description,
meta: state.customMethodCardMetaById,
persistedBlocks: state.customMethodCardFieldBlocksById,
draftFieldBlocks,
facetPrefill: pendingDraft
? {
group: "decisionApproaches",
draft: pendingDraft,
headings: da.sectionHeadings,
}
: undefined,
}),
);
setWizardCustomizeCardId(pendingCardId);
setCreateModalOpen(false);
setAddCustomWizardOpen(true);
}, [
da.confirmModal.description,
da.confirmModal.title,
da.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.decisionApproachDetailsById?.[pendingCardId],
() => decisionApproachPresetFor(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.decisionApproachDetailsById,
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,
decisionApproachDetailsById: 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.customMethodCardFieldBlocksById,
state.customMethodCardMetaById,
state.decisionApproachDetailsById,
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.decisionApproachDetailsById?.[pendingCardId],
() => decisionApproachPresetFor(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.decisionApproachDetailsById,
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,
decisionApproachDetailsById: 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.customMethodCardFieldBlocksById,
state.customMethodCardMetaById,
state.decisionApproachDetailsById,
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 handleToggleExpand = useCallback(() => {
markCreateFlowInteraction();
setExpanded((prev) => !prev);
}, [markCreateFlowInteraction]);
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({
selectedDecisionApproachIds: moveFacetSelectionIdToFront(
selectedIds,
existingId,
),
customMethodCardMetaById: methodCardMetaWithCustomizeHeader(
state.customMethodCardMetaById,
existingId,
{ title, description },
),
...(pendingDraft
? {
decisionApproachDetailsById: {
...(state.decisionApproachDetailsById ?? {}),
[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({
selectedDecisionApproachIds: moveFacetSelectionIdToFront(
selectedIds,
id,
),
customMethodCardMetaById: {
...(state.customMethodCardMetaById ?? {}),
[id]: { label: title, supportText: description },
},
decisionApproachDetailsById: {
...(state.decisionApproachDetailsById ?? {}),
[id]: decisionApproachPresetFor(id),
},
customMethodCardFieldBlocksById: {
...(state.customMethodCardFieldBlocksById ?? {}),
[id]: fieldBlocks,
},
});
},
[
markCreateFlowInteraction,
pendingDraft,
selectedIds,
state.customMethodCardFieldBlocksById,
state.customMethodCardMetaById,
state.decisionApproachDetailsById,
updateState,
wizardCustomizeCardId,
],
);
const handleCreateModalPrimary = useCallback(() => {
if (!pendingCardId) {
void handleCreateModalClose();
return;
}
markCreateFlowInteraction();
const persistWizardBlocks =
modalUsesWizardFieldBlocksBody && draftFieldBlocks !== null;
if (selectedIds.includes(pendingCardId)) {
replaceState((prev) => {
if (persistWizardBlocks) {
return {
...prev,
customMethodCardFieldBlocksById: {
...(prev.customMethodCardFieldBlocksById ?? {}),
[pendingCardId]: structuredClone(draftFieldBlocks ?? []),
},
};
}
if (!pendingDraft) {
return prev;
}
return {
...prev,
decisionApproachDetailsById: {
...(prev.decisionApproachDetailsById ?? {}),
[pendingCardId]: structuredClone(pendingDraft),
},
};
});
pendingEphemeralDuplicateIdRef.current = null;
customizeSnapshotRef.current = null;
void handleCreateModalClose();
return;
}
if (!pendingDraft) {
void handleCreateModalClose();
return;
}
replaceState((prev) => ({
...prev,
selectedDecisionApproachIds: moveFacetSelectionIdToFront(
prev.selectedDecisionApproachIds ?? [],
pendingCardId,
),
decisionApproachDetailsById: {
...(prev.decisionApproachDetailsById ?? {}),
[pendingCardId]: structuredClone(pendingDraft),
},
...(persistWizardBlocks
? {
customMethodCardFieldBlocksById: {
...(prev.customMethodCardFieldBlocksById ?? {}),
[pendingCardId]: structuredClone(draftFieldBlocks ?? []),
},
}
: {}),
}));
pendingEphemeralDuplicateIdRef.current = null;
customizeSnapshotRef.current = null;
void handleCreateModalClose();
}, [
draftFieldBlocks,
handleCreateModalClose,
markCreateFlowInteraction,
modalUsesWizardFieldBlocksBody,
pendingCardId,
pendingDraft,
replaceState,
selectedIds,
]);
const modalConfig = pendingCardId
? (() => {
const method = methodById.get(pendingCardId);
const meta = state.customMethodCardMetaById?.[pendingCardId];
const saveLabel = modalKebabMenu.saveEdits;
return {
title: meta?.label ?? method?.label ?? da.confirmModal.title,
description:
meta?.supportText ??
method?.supportText ??
da.confirmModal.description,
nextButtonText: isSelectedCardModal
? saveLabel
: da.addApproach.nextButtonText,
};
})()
: {
title: da.confirmModal.title,
description: da.confirmModal.description,
nextButtonText: da.confirmModal.nextButtonText,
};
return (
<>
<CreateFlowTwoColumnSelectShell
contentTopBelowMd="space-800"
lgVerticalAlign="start"
header={
<div className="flex w-full min-w-0 flex-col gap-3">
<HeaderLockup
title={da.sidebar.title}
description={sidebarDescription}
size={mdUp ? "L" : "M"}
justification={mdUp ? "left" : "center"}
/>
<InfoMessageBox
title={da.messageBox.title}
items={messageBoxItems}
checkedIds={messageBoxCheckedIds}
onCheckboxChange={handleMessageBoxCheckboxChange}
/>
</div>
}
>
<div
className="flex w-full min-w-0 flex-col items-stretch gap-6 py-0"
aria-busy={!recommendationsReady}
>
{recommendationsReady && (
<CardStack
cards={sampleCards}
selectedIds={selectedIds}
onCardSelect={handleCardSelect}
expanded={expanded}
onToggleExpand={handleToggleExpand}
hasMore={true}
toggleLabel={da.cardStack.toggleSeeAll}
showLessLabel={da.cardStack.toggleShowLess}
title=""
description={
expanded ? (
<>
{da.cardStack.expandedStackDescriptionBefore}
<InlineTextButton onClick={handleOpenAddWizard}>
{da.sidebar.descriptionLinkLabel}
</InlineTextButton>
{da.cardStack.expandedStackDescriptionAfter}
</>
) : (
""
)
}
layout="singleStack"
compactRecommendedLimit={5}
compactCardIds={compactCardIds}
className="w-full"
headerLockupSize={mdUp ? "L" : "M"}
/>
)}
</div>
<Create
isOpen={createModalOpen}
onClose={handleCreateModalClose}
onNext={handleCreateModalPrimary}
title={modalConfig.title}
description={modalConfig.description}
nextButtonText={modalConfig.nextButtonText}
showBackButton={false}
showNextButton={showMethodModalPrimary}
showRemoveButton={isSelectedCardModal}
onRemove={handleRemoveSelectedFromModal}
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)
}
/>
) : (
<DecisionApproachEditFields
value={pendingDraft}
onChange={handleDraftChange}
generateDraft={decisionApproachPresetFor(pendingCardId)}
/>
)
) : null}
</Create>
</CreateFlowTwoColumnSelectShell>
<CustomMethodCardWizard
isOpen={addCustomWizardOpen}
onClose={handleCloseAddWizard}
initialValues={wizardInitialValues}
onFinalize={handleFinalizeCustomCard}
onPersistCustomUploadFile={(file) =>
uploadCreateFlowFile(file, "customMethodAttachment")
}
/>
{confirmDialog}
</>
);
}