Final review edit modals created
This commit is contained in:
@@ -7,6 +7,11 @@
|
||||
* Lives under `screens/card/` (not `select/`): Figma **card stack** layout is a distinct shell from
|
||||
* two-column chip **select** frames. Future card-stack steps get their own `*Screen.tsx` here and
|
||||
* reuse `CardStack` / `CreateFlowStepShell` as needed.
|
||||
*
|
||||
* Card click opens the Figma "Add Platform" create modal (node `20246-15829`) with three
|
||||
* editable sections rendered by {@link CommunicationMethodEditFields}. The same field set is
|
||||
* reused on `/create/final-review` — see `FinalReviewChipEditModal`. Confirm persists both
|
||||
* the chip selection and any user edits as a `communicationMethodDetailsById[id]` override.
|
||||
*/
|
||||
|
||||
import { useState, useCallback, useMemo } from "react";
|
||||
@@ -27,61 +32,9 @@ import {
|
||||
CREATE_FLOW_CARD_STACK_AREA_MAX_CLASS,
|
||||
CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS,
|
||||
} from "../../components/createFlowLayoutTokens";
|
||||
import ModalTextAreaField from "../../components/ModalTextAreaField";
|
||||
|
||||
const SECTION_FIELDS = [
|
||||
"corePrinciple",
|
||||
"logisticsAdmin",
|
||||
"codeOfConduct",
|
||||
] as const;
|
||||
type SectionField = (typeof SECTION_FIELDS)[number];
|
||||
|
||||
function AddPlatformModalContent({
|
||||
platformCardId,
|
||||
}: {
|
||||
platformCardId: string;
|
||||
}) {
|
||||
const { markCreateFlowInteraction } = useCreateFlow();
|
||||
const m = useMessages();
|
||||
const comm = m.create.customRule.communication;
|
||||
const method = comm.methods.find((entry) => entry.id === platformCardId);
|
||||
const sections = method?.sections;
|
||||
const defaults: Record<SectionField, string> = {
|
||||
corePrinciple: sections?.corePrinciple ?? "",
|
||||
logisticsAdmin: sections?.logisticsAdmin ?? "",
|
||||
codeOfConduct: sections?.codeOfConduct ?? "",
|
||||
};
|
||||
|
||||
const [sectionValues, setSectionValues] = useState<
|
||||
Record<SectionField, string>
|
||||
>(() => ({
|
||||
corePrinciple: defaults.corePrinciple,
|
||||
logisticsAdmin: defaults.logisticsAdmin,
|
||||
codeOfConduct: defaults.codeOfConduct,
|
||||
}));
|
||||
|
||||
const updateSection = useCallback(
|
||||
(key: SectionField, value: string) => {
|
||||
markCreateFlowInteraction();
|
||||
setSectionValues((prev) => ({ ...prev, [key]: value }));
|
||||
},
|
||||
[markCreateFlowInteraction],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6">
|
||||
{SECTION_FIELDS.map((field) => (
|
||||
<ModalTextAreaField
|
||||
key={field}
|
||||
label={comm.sectionHeadings[field]}
|
||||
rows={6}
|
||||
value={sectionValues[field]}
|
||||
onChange={(v) => updateSection(field, v)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
import { CommunicationMethodEditFields } from "../../components/methodEditFields";
|
||||
import { communicationPresetFor } from "../../../../../lib/create/finalReviewChipPresets";
|
||||
import type { CommunicationMethodDetailEntry } from "../../types";
|
||||
|
||||
export function CommunicationMethodsScreen() {
|
||||
const m = useMessages();
|
||||
@@ -91,16 +44,11 @@ export function CommunicationMethodsScreen() {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const [createModalOpen, setCreateModalOpen] = useState(false);
|
||||
const [pendingCardId, setPendingCardId] = useState<string | null>(null);
|
||||
const [pendingDraft, setPendingDraft] =
|
||||
useState<CommunicationMethodDetailEntry | null>(null);
|
||||
|
||||
const selectedIds = state.selectedCommunicationMethodIds ?? [];
|
||||
|
||||
const setSelectedIds = useCallback(
|
||||
(next: string[]) => {
|
||||
updateState({ selectedCommunicationMethodIds: next });
|
||||
},
|
||||
[updateState],
|
||||
);
|
||||
|
||||
const { scoresBySlug, hasAnyFacets } =
|
||||
useFacetRecommendations("communication");
|
||||
const rankedMethods = useMemo(
|
||||
@@ -148,55 +96,81 @@ export function CommunicationMethodsScreen() {
|
||||
</>
|
||||
);
|
||||
|
||||
const modalConfig = (() => {
|
||||
if (!pendingCardId) {
|
||||
return {
|
||||
const modalConfig = pendingCardId
|
||||
? (() => {
|
||||
const method = methodById.get(pendingCardId);
|
||||
return {
|
||||
title: method?.label ?? comm.confirmModal.title,
|
||||
description: method?.supportText ?? comm.confirmModal.description,
|
||||
nextButtonText: comm.addPlatform.nextButtonText,
|
||||
};
|
||||
})()
|
||||
: {
|
||||
title: comm.confirmModal.title,
|
||||
description: comm.confirmModal.description,
|
||||
nextButtonText: comm.confirmModal.nextButtonText,
|
||||
showBackButton: false as const,
|
||||
currentStep: undefined,
|
||||
totalSteps: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const method = methodById.get(pendingCardId);
|
||||
return {
|
||||
title: method?.label ?? comm.confirmModal.title,
|
||||
description: method?.supportText ?? comm.confirmModal.description,
|
||||
nextButtonText: comm.addPlatform.nextButtonText,
|
||||
showBackButton: false as const,
|
||||
currentStep: undefined,
|
||||
totalSteps: undefined,
|
||||
};
|
||||
})();
|
||||
const seedDraft = useCallback(
|
||||
(id: string): CommunicationMethodDetailEntry => {
|
||||
const saved = state.communicationMethodDetailsById?.[id];
|
||||
if (saved) {
|
||||
return { ...saved };
|
||||
}
|
||||
return communicationPresetFor(id);
|
||||
},
|
||||
[state.communicationMethodDetailsById],
|
||||
);
|
||||
|
||||
const handleCardClick = useCallback(
|
||||
(id: string) => {
|
||||
markCreateFlowInteraction();
|
||||
setPendingCardId(id);
|
||||
setPendingDraft(seedDraft(id));
|
||||
setCreateModalOpen(true);
|
||||
},
|
||||
[markCreateFlowInteraction, seedDraft],
|
||||
);
|
||||
|
||||
const handleDraftChange = useCallback(
|
||||
(next: CommunicationMethodDetailEntry) => {
|
||||
markCreateFlowInteraction();
|
||||
setPendingDraft(next);
|
||||
},
|
||||
[markCreateFlowInteraction],
|
||||
);
|
||||
|
||||
const handleCreateModalClose = useCallback(() => {
|
||||
setCreateModalOpen(false);
|
||||
setPendingCardId(null);
|
||||
setPendingDraft(null);
|
||||
}, []);
|
||||
|
||||
const handleCreateModalConfirm = useCallback(() => {
|
||||
markCreateFlowInteraction();
|
||||
if (pendingCardId) {
|
||||
setSelectedIds(
|
||||
selectedIds.includes(pendingCardId)
|
||||
? selectedIds
|
||||
: [...selectedIds, pendingCardId],
|
||||
);
|
||||
if (!pendingCardId || !pendingDraft) {
|
||||
handleCreateModalClose();
|
||||
return;
|
||||
}
|
||||
setCreateModalOpen(false);
|
||||
setPendingCardId(null);
|
||||
}, [markCreateFlowInteraction, pendingCardId, selectedIds, setSelectedIds]);
|
||||
markCreateFlowInteraction();
|
||||
updateState({
|
||||
selectedCommunicationMethodIds: selectedIds.includes(pendingCardId)
|
||||
? selectedIds
|
||||
: [...selectedIds, pendingCardId],
|
||||
communicationMethodDetailsById: {
|
||||
...(state.communicationMethodDetailsById ?? {}),
|
||||
[pendingCardId]: pendingDraft,
|
||||
},
|
||||
});
|
||||
handleCreateModalClose();
|
||||
}, [
|
||||
handleCreateModalClose,
|
||||
markCreateFlowInteraction,
|
||||
pendingCardId,
|
||||
pendingDraft,
|
||||
selectedIds,
|
||||
state.communicationMethodDetailsById,
|
||||
updateState,
|
||||
]);
|
||||
|
||||
return (
|
||||
<CreateFlowStepShell
|
||||
@@ -238,15 +212,14 @@ export function CommunicationMethodsScreen() {
|
||||
title={modalConfig.title}
|
||||
description={modalConfig.description}
|
||||
nextButtonText={modalConfig.nextButtonText}
|
||||
showBackButton={modalConfig.showBackButton}
|
||||
currentStep={modalConfig.currentStep}
|
||||
totalSteps={modalConfig.totalSteps}
|
||||
showBackButton={false}
|
||||
backdropVariant="loginYellow"
|
||||
>
|
||||
{pendingCardId ? (
|
||||
<AddPlatformModalContent
|
||||
{pendingCardId && pendingDraft ? (
|
||||
<CommunicationMethodEditFields
|
||||
key={pendingCardId}
|
||||
platformCardId={pendingCardId}
|
||||
value={pendingDraft}
|
||||
onChange={handleDraftChange}
|
||||
/>
|
||||
) : null}
|
||||
</Create>
|
||||
|
||||
Reference in New Issue
Block a user