Files
community-rule/app/(app)/create/screens/select/CoreValuesSelectScreen.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

821 lines
26 KiB
TypeScript

"use client";
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import MultiSelect from "../../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../../components/controls/MultiSelect/MultiSelect.types";
import Create from "../../../../components/modals/Create";
import ContentLockup from "../../../../components/type/ContentLockup";
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,
} from "../../types";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowTwoColumnSelectShell } from "../../components/CreateFlowTwoColumnSelectShell";
import { CoreValueEditFields } from "../../components/methodEditFields";
import CustomMethodCardModalBody from "../../components/CustomMethodCardModalBody";
import CustomMethodCardWizard from "../../components/CustomMethodCardWizard";
import { usesWizardFieldBlocksModalBody } from "../../../../../lib/create/usesWizardFieldBlocksModalBody";
import { buildCustomRuleModalKebabMenu } from "../../components/customRuleModalKebabMenu";
import {
duplicateCoreValueChipInDraft,
MAX_SELECTED_CORE_VALUES,
removeCoreValueChipFromDraft,
} from "../../../../../lib/create/coreValueChipFacet";
import { methodCardMetaWithCustomizeHeader } from "../../../../../lib/create/methodCardCustomizeMetaPatch";
import { moveFacetSelectionIdToFront } from "../../../../../lib/create/methodCardSelectionOrder";
import {
buildMethodCardWizardInitialValues,
coreValueDetailsFromWizardFieldBlocks,
overlayFacetPrefillValues,
type MethodCardWizardInitialValues,
} from "../../../../../lib/create/methodCardWizardPrefill";
import type { CustomMethodCardFieldBlock } from "../../../../../lib/create/customMethodCardFieldBlocks";
import { uploadCreateFlowFile } from "../../../../../lib/create/uploadToServer";
const MAX_CORE_VALUES = MAX_SELECTED_CORE_VALUES;
/**
* Why three sessions, not two:
*
* - `pending` — preset chip just selected; modal opened to capture
* meaning/signals. Close (X) confirms, then unselects the chip.
* - `customPending` — leftover inline custom-chip drafts (older sessions).
* Dismiss = drop the chip entirely.
* - `editing` — chip already exists & is selected; modal reopened to
* tweak meaning/signals. Dismiss = no-op (chip stays as-is).
*
* **Add value** (and the header "add" link) opens an empty custom-policy
* wizard. Finalize writes a selected chip named from the wizard title.
*/
type ModalSession = "pending" | "customPending" | "editing";
/** Row in `coreValues.json` `values` — string (legacy) or `{ label, meaning, signals }`. */
type CoreValuePresetJson =
| string
| { label: string; meaning?: string; signals?: string };
type CoreValuePreset = {
label: string;
meaning: string;
signals: string;
};
function normalizeCoreValuePresets(
values: readonly CoreValuePresetJson[],
): CoreValuePreset[] {
return values.map((v) => {
if (typeof v === "string") {
return { label: v, meaning: "", signals: "" };
}
return {
label: v.label,
meaning: typeof v.meaning === "string" ? v.meaning : "",
signals: typeof v.signals === "string" ? v.signals : "",
};
});
}
function selectedIdsFromOptions(options: ChipOption[]): string[] {
return options
.filter((o) => o.state === "selected")
.map((o) => o.id);
}
function chipOptionsToSnapshotRows(
options: ChipOption[],
): CommunityStructureChipSnapshotRow[] {
return options.map((o) => ({
id: o.id,
label: o.label,
...(o.state !== undefined ? { state: o.state } : {}),
}));
}
const EMPTY_DETAIL: CoreValueDetailEntry = { meaning: "", signals: "" };
/** Create Custom — Core Values (Figma `20264:68378`). Up to five selections; preset list + custom chips. */
export function CoreValuesSelectScreen() {
const m = useMessages();
const cv = m.create.customRule.coreValues;
const modalKebabMenu = m.create.customRule.modalKebabMenu;
const presets = useMemo(
() => normalizeCoreValuePresets(cv.values as CoreValuePresetJson[]),
[cv.values],
);
const { requestConfirm, confirmDialog } = useAsyncConfirm();
const { markCreateFlowInteraction, updateState, replaceState, state } =
useCreateFlow();
const initialDraftRef = useRef<CoreValueDetailEntry | null>(null);
const pendingEphemeralCoreDuplicateRef = useRef<string | null>(null);
const [coreValueOptions, setCoreValueOptions] = useState<ChipOption[]>(() =>
buildCoreValueChipOptionsFromDraft(
presets,
state.coreValuesChipsSnapshot,
state.selectedCoreValueIds,
),
);
const [activeModalChipId, setActiveModalChipId] = useState<string | null>(
null,
);
const [modalSession, setModalSession] = useState<ModalSession | null>(null);
const [draft, setDraft] = useState<CoreValueDetailEntry>(EMPTY_DETAIL);
const [addCustomWizardOpen, setAddCustomWizardOpen] = useState(false);
const [wizardCustomizeChipId, setWizardCustomizeChipId] = useState<
string | null
>(null);
const [wizardInitialValues, setWizardInitialValues] =
useState<MethodCardWizardInitialValues | null>(null);
const [draftFieldBlocks, setDraftFieldBlocks] = useState<
CustomMethodCardFieldBlock[] | null
>(null);
useEffect(() => {
setCoreValueOptions(
buildCoreValueChipOptionsFromDraft(
presets,
state.coreValuesChipsSnapshot,
state.selectedCoreValueIds,
),
);
}, [
presets,
state.coreValuesChipsSnapshot,
state.selectedCoreValueIds,
]);
/** Sync chips to create-flow draft. Never call `updateState` from inside a `setCoreValueOptions` updater — defer with `queueMicrotask`. */
const syncCoreValuesToDraft = useCallback(
(next: ChipOption[]) => {
updateState({
selectedCoreValueIds: selectedIdsFromOptions(next),
coreValuesChipsSnapshot: chipOptionsToSnapshotRows(next),
});
},
[updateState],
);
const persistCoreValues = useCallback(
(next: ChipOption[]) => {
markCreateFlowInteraction();
setCoreValueOptions(next);
syncCoreValuesToDraft(next);
},
[markCreateFlowInteraction, syncCoreValuesToDraft],
);
/** Default meaning/signals from `coreValues.json` `values` for each preset label. */
const getPresetTexts = useCallback(
(valueLabel: string): CoreValueDetailEntry => {
const row = presets.find((p) => p.label === valueLabel);
if (!row) return EMPTY_DETAIL;
return { meaning: row.meaning, signals: row.signals };
},
[presets],
);
const getInitialTexts = useCallback(
(chipId: string, _valueLabel: string): CoreValueDetailEntry => {
const saved = state.coreValueDetailsByChipId?.[chipId];
if (!saved) return EMPTY_DETAIL;
return {
meaning: saved.meaning,
signals: saved.signals,
...(saved.supportText ? { supportText: saved.supportText } : {}),
};
},
[state.coreValueDetailsByChipId],
);
const openModal = useCallback(
(
chipId: string,
session: ModalSession,
valueLabel: string,
seedDetail?: CoreValueDetailEntry,
) => {
const initial = seedDetail ?? getInitialTexts(chipId, valueLabel);
initialDraftRef.current = { ...initial };
const persisted = state.customMethodCardFieldBlocksById?.[chipId];
setDraftFieldBlocks(
Array.isArray(persisted) && persisted.length > 0
? structuredClone(persisted)
: null,
);
setDraft(initial);
setActiveModalChipId(chipId);
setModalSession(session);
markCreateFlowInteraction();
},
[
getInitialTexts,
markCreateFlowInteraction,
state.customMethodCardFieldBlocksById,
],
);
const handleDraftChange = useCallback(
(next: CoreValueDetailEntry) => {
markCreateFlowInteraction();
setDraft(next);
},
[markCreateFlowInteraction],
);
const finalizeModalDismiss = useCallback(() => {
pendingEphemeralCoreDuplicateRef.current = null;
initialDraftRef.current = null;
setActiveModalChipId(null);
setModalSession(null);
setDraftFieldBlocks(null);
}, []);
const confirmLeaveWithoutSaving = useCallback(async () => {
const initial = initialDraftRef.current;
const fieldsDirty =
initial != null &&
(draft.meaning !== initial.meaning || draft.signals !== initial.signals);
if (!fieldsDirty) {
return true;
}
const isPendingAdd =
modalSession === "pending" || modalSession === "customPending";
return requestConfirm({
title: cv.detailModal.discardTitle,
description: isPendingAdd
? cv.detailModal.discardPendingDescription
: cv.detailModal.discardEditsDescription,
proceedText: cv.detailModal.discardProceed,
cancelText: cv.detailModal.discardKeepEditing,
});
}, [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();
const priorEphemeral = pendingEphemeralCoreDuplicateRef.current;
let outcome: ReturnType<typeof duplicateCoreValueChipInDraft> | null = null;
replaceState((prev) => {
const base =
priorEphemeral != null
? { ...prev, ...removeCoreValueChipFromDraft(prev, priorEphemeral) }
: prev;
const res = duplicateCoreValueChipInDraft(
base,
activeModalChipId,
modalKebabMenu.duplicateTitleSuffix,
);
if (!res) {
return base;
}
outcome = res;
return { ...base, ...res.patch };
});
if (!outcome) {
return;
}
pendingEphemeralCoreDuplicateRef.current = outcome.newId;
openModal(
outcome.newId,
"editing",
outcome.newLabel,
structuredClone(draft),
);
}, [
activeModalChipId,
draft,
markCreateFlowInteraction,
modalKebabMenu.duplicateTitleSuffix,
modalSession,
openModal,
replaceState,
]);
const handleRemoveFromKebab = useCallback(() => {
markCreateFlowInteraction();
const ep = pendingEphemeralCoreDuplicateRef.current;
if (ep && activeModalChipId === ep) {
replaceState((prev) => ({
...prev,
...removeCoreValueChipFromDraft(prev, ep),
}));
finalizeModalDismiss();
return;
}
if (modalSession === "pending") {
const next = coreValueOptions.map((opt) =>
opt.id === activeModalChipId
? { ...opt, state: "unselected" as const }
: opt,
);
persistCoreValues(next);
} else if (modalSession === "customPending") {
const next = coreValueOptions.filter((opt) => opt.id !== activeModalChipId);
persistCoreValues(next);
} else if (modalSession === "editing" && activeModalChipId) {
const nextFiltered = coreValueOptions.filter(
(opt) => opt.id !== activeModalChipId,
);
markCreateFlowInteraction();
replaceState((prev) => ({
...prev,
...removeCoreValueChipFromDraft(prev, activeModalChipId),
}));
setCoreValueOptions(nextFiltered);
}
finalizeModalDismiss();
}, [
activeModalChipId,
coreValueOptions,
finalizeModalDismiss,
markCreateFlowInteraction,
modalSession,
persistCoreValues,
replaceState,
]);
const handleModalDismiss = useCallback(async () => {
if (!(await confirmLeaveWithoutSaving())) {
return;
}
const ep = pendingEphemeralCoreDuplicateRef.current;
if (ep) {
replaceState((prev) => ({
...prev,
...removeCoreValueChipFromDraft(prev, ep),
}));
}
if (modalSession === "pending" && activeModalChipId) {
const next = coreValueOptions.map((opt) =>
opt.id === activeModalChipId
? { ...opt, state: "unselected" as const }
: opt,
);
persistCoreValues(next);
} else if (modalSession === "customPending" && activeModalChipId) {
const next = coreValueOptions.filter(
(opt) => opt.id !== activeModalChipId,
);
persistCoreValues(next);
}
finalizeModalDismiss();
}, [
activeModalChipId,
confirmLeaveWithoutSaving,
coreValueOptions,
finalizeModalDismiss,
modalSession,
persistCoreValues,
replaceState,
]);
const handleModalConfirm = useCallback(() => {
if (!activeModalChipId || !modalSession) return;
markCreateFlowInteraction();
pendingEphemeralCoreDuplicateRef.current = null;
const existingBlocks =
draftFieldBlocks && draftFieldBlocks.length > 0
? draftFieldBlocks
: state.customMethodCardFieldBlocksById?.[activeModalChipId];
updateState({
coreValueDetailsByChipId: {
...(state.coreValueDetailsByChipId ?? {}),
[activeModalChipId]: draft,
},
...(existingBlocks && existingBlocks.length > 0
? {
customMethodCardFieldBlocksById: {
...(state.customMethodCardFieldBlocksById ?? {}),
[activeModalChipId]: overlayFacetPrefillValues(existingBlocks, {
group: "coreValues",
draft,
headings: {
meaning: cv.detailModal.meaningLabel,
signals: cv.detailModal.signalsLabel,
},
}),
},
}
: {}),
});
finalizeModalDismiss();
}, [
activeModalChipId,
cv.detailModal.meaningLabel,
cv.detailModal.signalsLabel,
draft,
draftFieldBlocks,
finalizeModalDismiss,
markCreateFlowInteraction,
modalSession,
state.coreValueDetailsByChipId,
state.customMethodCardFieldBlocksById,
updateState,
]);
const modalChipLabel =
coreValueOptions.find((o) => o.id === activeModalChipId)?.label ?? "";
const modalUsesWizardFieldBlocksBody = Boolean(
activeModalChipId &&
usesWizardFieldBlocksModalBody({
methodId: activeModalChipId,
meta: {},
fieldBlocksById: state.customMethodCardFieldBlocksById,
modalEditUnlocked: true,
draftFieldBlocks,
}),
);
const showFooterPrimary = Boolean(modalSession);
const handleCustomize = useCallback(() => {
if (!activeModalChipId) return;
markCreateFlowInteraction();
setWizardInitialValues(
buildMethodCardWizardInitialValues({
cardId: activeModalChipId,
fallbackTitle: modalChipLabel,
fallbackDescription:
draft.supportText?.trim() || cv.detailModal.subtitle,
meta: {},
persistedBlocks: state.customMethodCardFieldBlocksById,
draftFieldBlocks,
facetPrefill: {
group: "coreValues",
draft,
headings: {
meaning: cv.detailModal.meaningLabel,
signals: cv.detailModal.signalsLabel,
},
},
}),
);
setWizardCustomizeChipId(activeModalChipId);
setAddCustomWizardOpen(true);
}, [
activeModalChipId,
cv.detailModal.meaningLabel,
cv.detailModal.signalsLabel,
cv.detailModal.subtitle,
draft,
draftFieldBlocks,
markCreateFlowInteraction,
modalChipLabel,
state.customMethodCardFieldBlocksById,
]);
const handleCloseAddWizard = useCallback(() => {
setAddCustomWizardOpen(false);
setWizardCustomizeChipId(null);
setWizardInitialValues(null);
}, []);
const handleFinalizeCustomCard = useCallback(
({
title,
description,
fieldBlocks,
}: {
title: string;
description: string;
fieldBlocks: CustomMethodCardFieldBlock[];
}) => {
const trimmedTitle = title.trim();
const trimmedDescription = description.trim();
if (!trimmedTitle) return;
markCreateFlowInteraction();
pendingEphemeralCoreDuplicateRef.current = null;
const existingId = wizardCustomizeChipId;
if (!existingId) {
const id = crypto.randomUUID();
const nextDetails = {
...coreValueDetailsFromWizardFieldBlocks(fieldBlocks, EMPTY_DETAIL),
...(trimmedDescription.length > 0
? { supportText: trimmedDescription }
: {}),
};
replaceState((prev) => {
const sel = prev.selectedCoreValueIds ?? [];
if (sel.length >= MAX_CORE_VALUES) {
return prev;
}
const snap = [...(prev.coreValuesChipsSnapshot ?? [])];
snap.push({
id,
label: trimmedTitle,
state: "selected",
});
return {
...prev,
selectedCoreValueIds: moveFacetSelectionIdToFront(sel, id),
coreValuesChipsSnapshot: snap,
coreValueDetailsByChipId: {
...(prev.coreValueDetailsByChipId ?? {}),
[id]: nextDetails,
},
customMethodCardFieldBlocksById: {
...(prev.customMethodCardFieldBlocksById ?? {}),
[id]: structuredClone(fieldBlocks),
},
customMethodCardMetaById: methodCardMetaWithCustomizeHeader(
prev.customMethodCardMetaById,
id,
{ title: trimmedTitle, description: trimmedDescription },
),
};
});
setAddCustomWizardOpen(false);
setWizardCustomizeChipId(null);
setWizardInitialValues(null);
return;
}
const nextDetails = {
...coreValueDetailsFromWizardFieldBlocks(fieldBlocks, draft),
...(trimmedDescription.length > 0
? { supportText: trimmedDescription }
: {}),
};
replaceState((prev) => {
const snap = [...(prev.coreValuesChipsSnapshot ?? [])];
const i = snap.findIndex((r) => r.id === existingId);
if (i >= 0) {
snap[i] = { ...snap[i], label: trimmedTitle };
}
return {
...prev,
coreValuesChipsSnapshot: snap,
coreValueDetailsByChipId: {
...(prev.coreValueDetailsByChipId ?? {}),
[existingId]: nextDetails,
},
customMethodCardFieldBlocksById: {
...(prev.customMethodCardFieldBlocksById ?? {}),
[existingId]: structuredClone(fieldBlocks),
},
};
});
setDraft(nextDetails);
setDraftFieldBlocks(structuredClone(fieldBlocks));
setAddCustomWizardOpen(false);
setWizardCustomizeChipId(null);
setWizardInitialValues(null);
},
[draft, markCreateFlowInteraction, replaceState, wizardCustomizeChipId],
);
const selectedCount = useMemo(
() => coreValueOptions.filter((o) => o.state === "selected").length,
[coreValueOptions],
);
const atSelectionLimit = selectedCount >= MAX_CORE_VALUES;
const selectionCountText = cv.multiSelect.selectionCount
.replace("{count}", String(selectedCount))
.replace("{max}", String(MAX_CORE_VALUES));
const kebabMenuItems = useMemo(() => {
if (!modalSession || !activeModalChipId) return [];
return buildCustomRuleModalKebabMenu(modalKebabMenu, {
showCustomize: true,
onCustomize: handleCustomize,
onDuplicate:
(state.editingPublishedRuleId?.trim() ?? "") !== "" ||
atSelectionLimit
? undefined
: handleDuplicateCoreChip,
showRemove: modalSession === "editing",
onRemove: handleRemoveFromKebab,
});
}, [
activeModalChipId,
atSelectionLimit,
handleCustomize,
handleDuplicateCoreChip,
handleRemoveFromKebab,
modalKebabMenu,
modalSession,
state.editingPublishedRuleId,
]);
const handleChipClick = (chipId: string) => {
const target = coreValueOptions.find((o) => o.id === chipId);
if (!target || target.state === "custom") return;
const selectedCount = coreValueOptions.filter(
(o) => o.state === "selected",
).length;
if (target.state === "selected") {
openModal(chipId, "editing", target.label);
return;
}
if (selectedCount >= MAX_CORE_VALUES) return;
const next: ChipOption[] = coreValueOptions.map((opt) =>
opt.id === chipId
? { ...opt, state: "selected" as const }
: opt,
);
persistCoreValues(next);
openModal(chipId, "pending", target.label);
};
const addHandlers = {
onAddClick: () => {
const selectedCount = coreValueOptions.filter(
(o) => o.state === "selected",
).length;
if (selectedCount >= MAX_CORE_VALUES) return;
markCreateFlowInteraction();
setWizardCustomizeChipId(null);
setWizardInitialValues(null);
setAddCustomWizardOpen(true);
},
onCustomChipConfirm: (chipId: string, value: string) => {
markCreateFlowInteraction();
setCoreValueOptions((prev) => {
const withLabel = prev.map((opt) =>
opt.id === chipId
? { ...opt, label: value, state: "unselected" as const }
: opt,
);
const selectedCount = withLabel.filter(
(o) => o.state === "selected",
).length;
const canSelect = selectedCount < MAX_CORE_VALUES;
const next = canSelect
? withLabel.map((opt) =>
opt.id === chipId
? { ...opt, state: "selected" as const }
: opt,
)
: withLabel;
queueMicrotask(() => {
syncCoreValuesToDraft(next);
// Both branches treat the chip as a brand-new draft until the
// user confirms via Add Value — dismissal removes it.
openModal(chipId, "customPending", value);
});
return next;
});
},
onCustomChipClose: (chipId: string) => {
markCreateFlowInteraction();
setCoreValueOptions((prev) => {
const next = prev.filter((o) => o.id !== chipId);
queueMicrotask(() => syncCoreValuesToDraft(next));
return next;
});
},
};
const description = (
<>
<span className="leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
{cv.header.descriptionLead}{" "}
</span>
<button
type="button"
onClick={addHandlers.onAddClick}
disabled={atSelectionLimit}
className="cursor-pointer font-normal leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)] underline decoration-solid underline-offset-[3px] hover:opacity-90 disabled:cursor-not-allowed disabled:no-underline disabled:opacity-60 disabled:hover:opacity-60"
>
{cv.header.addLink}
</button>
<span className="leading-[1.3] text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
{" "}
{cv.header.descriptionTrail}
</span>
</>
);
const detailModal = cv.detailModal;
return (
<>
<CreateFlowTwoColumnSelectShell
lgVerticalAlign="start"
header={
<CreateFlowHeaderLockup
title={cv.header.title}
description={description}
justification="left"
/>
}
>
<MultiSelect
formHeader={false}
size="m"
options={coreValueOptions}
onChipClick={handleChipClick}
onAddClick={addHandlers.onAddClick}
onCustomChipConfirm={addHandlers.onCustomChipConfirm}
onCustomChipClose={addHandlers.onCustomChipClose}
addButton
addButtonText={cv.multiSelect.addButtonText}
maxSelections={MAX_CORE_VALUES}
selectionCountText={selectionCountText}
limitReachedAnnouncement={cv.multiSelect.limitReached}
/>
{detailModal && (
<Create
isOpen={activeModalChipId !== null && !addCustomWizardOpen}
onClose={handleModalDismiss}
backdropVariant="blurredYellow"
headerContent={
<div className="bg-[var(--color-surface-default-primary)] px-[24px] py-[12px] shrink-0">
<ContentLockup
title={modalChipLabel}
description={
draft.supportText?.trim() || detailModal.subtitle
}
variant="modal"
alignment="left"
/>
</div>
}
showBackButton={false}
showNextButton={showFooterPrimary}
showRemoveButton={modalSession === "editing"}
onRemove={handleRemoveFromKebab}
onNext={handleModalConfirm}
nextButtonText={
modalSession === "editing"
? modalKebabMenu.saveEdits
: detailModal.addValueButton
}
kebabTriggerAriaLabel={modalKebabMenu.triggerAriaLabel}
kebabMenuAriaLabel={modalKebabMenu.menuAriaLabel}
kebabMenuItems={
kebabMenuItems.length > 0 ? kebabMenuItems : undefined
}
ariaLabel={modalChipLabel || "Core value details"}
>
{modalUsesWizardFieldBlocksBody && activeModalChipId ? (
<CustomMethodCardModalBody
cardId={activeModalChipId}
blocksById={state.customMethodCardFieldBlocksById}
blocksOverride={
draftFieldBlocks !== null ? draftFieldBlocks : undefined
}
showPolicyContentLockupWhenNoBlocks={false}
onFieldBlocksChange={
draftFieldBlocks === null
? undefined
: (next) => {
setDraftFieldBlocks(next);
setDraft(
coreValueDetailsFromWizardFieldBlocks(next, draft),
);
}
}
/>
) : (
<CoreValueEditFields
value={draft}
onChange={handleDraftChange}
generateDraft={getPresetTexts(modalChipLabel)}
/>
)}
</Create>
)}
</CreateFlowTwoColumnSelectShell>
<CustomMethodCardWizard
isOpen={addCustomWizardOpen}
onClose={handleCloseAddWizard}
initialValues={wizardInitialValues}
onFinalize={handleFinalizeCustomCard}
onPersistCustomUploadFile={(file) =>
uploadCreateFlowFile(file, "customMethodAttachment")
}
/>
{confirmDialog}
</>
);
}