Implement modals across create flow

This commit is contained in:
adilallo
2026-04-17 23:45:29 -06:00
parent 36dcb79870
commit 4854c49c4a
21 changed files with 2089 additions and 318 deletions
@@ -16,23 +16,18 @@ import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import CardStack from "../../../components/utility/CardStack";
import Create from "../../../components/modals/Create";
import TextArea from "../../../components/controls/TextArea";
import InlineTextButton from "../../../components/buttons/InlineTextButton";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import {
CREATE_FLOW_CARD_STACK_AREA_MAX_CLASS,
CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS,
} from "../../components/createFlowLayoutTokens";
import ModalTextAreaField from "../../components/ModalTextAreaField";
const IN_PERSON_CARD_ID = "in-person-meetings";
const SIGNAL_CARD_ID = "signal";
const VIDEO_MEETINGS_CARD_ID = "video-meetings";
const ADD_PLATFORM_CARD_IDS = [
IN_PERSON_CARD_ID,
SIGNAL_CARD_ID,
VIDEO_MEETINGS_CARD_ID,
] as const;
const SECTION_FIELDS = [
"corePrinciple",
"logisticsAdmin",
@@ -50,40 +45,6 @@ const COMMUNICATION_CARD_ORDER = [
"7",
] as const;
function CreateModalSection({
title,
value: _value,
onChange,
}: {
title: string;
value: string;
onChange: (_value: string) => void;
}) {
return (
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2">
<h3 className="text-sm font-semibold leading-tight text-[var(--color-content-default-primary)]">
{title}
</h3>
<span
className="flex h-4 w-4 shrink-0 items-center justify-center rounded-full border border-[var(--color-content-invert-brand-secondary)] bg-transparent text-[10px] font-medium leading-none text-[var(--color-content-invert-brand-secondary)]"
aria-hidden
>
?
</span>
</div>
<TextArea
formHeader={false}
value={_value}
onChange={(e) => onChange(e.target.value)}
size="large"
rows={6}
appearance="embedded"
/>
</div>
);
}
function AddPlatformModalContent({
platformCardId,
}: {
@@ -92,15 +53,15 @@ function AddPlatformModalContent({
const { markCreateFlowInteraction } = useCreateFlow();
const m = useMessages();
const comm = m.create.communication;
const modal = comm.modals[platformCardId as keyof typeof comm.modals];
const defaults =
modal && "sections" in modal
? modal.sections
: {
corePrinciple: "",
logisticsAdmin: "",
codeOfConduct: "",
};
const modal =
platformCardId in comm.modals
? comm.modals[platformCardId as keyof typeof comm.modals]
: null;
const defaults = modal?.sections ?? {
corePrinciple: "",
logisticsAdmin: "",
codeOfConduct: "",
};
const [sectionValues, setSectionValues] = useState<
Record<SectionField, string>
@@ -118,14 +79,13 @@ function AddPlatformModalContent({
[markCreateFlowInteraction],
);
if (!modal || !("sections" in modal)) return null;
return (
<div className="flex flex-col gap-6">
{SECTION_FIELDS.map((field) => (
<CreateModalSection
<ModalTextAreaField
key={field}
title={comm.sectionHeadings[field]}
label={comm.sectionHeadings[field]}
rows={6}
value={sectionValues[field]}
onChange={(v) => updateSection(field, v)}
/>
@@ -134,13 +94,6 @@ function AddPlatformModalContent({
);
}
function isAddPlatformCard(cardId: string | null): boolean {
return (
cardId !== null &&
(ADD_PLATFORM_CARD_IDS as readonly string[]).includes(cardId)
);
}
export function CommunicationMethodsScreen() {
const m = useMessages();
const comm = m.create.communication;
@@ -180,42 +133,55 @@ export function CommunicationMethodsScreen() {
) : (
<>
{comm.page.compactDescriptionBefore}
<button
type="button"
className="cursor-pointer border-none bg-transparent p-0 font-inherit text-[length:inherit] leading-[inherit] text-[var(--color-content-default-tertiary)] underline decoration-solid underline-offset-2 hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-border-invert-primary)]"
<InlineTextButton
onClick={() => {
markCreateFlowInteraction();
setExpanded(true);
}}
>
{comm.page.compactDescriptionLinkLabel}
</button>
</InlineTextButton>
{comm.page.compactDescriptionAfter}
</>
);
const modalConfig =
pendingCardId && pendingCardId in comm.modals
? (() => {
const modal =
comm.modals[pendingCardId as keyof typeof comm.modals];
return {
title: modal.title,
description: modal.description,
nextButtonText: comm.addPlatform.nextButtonText,
showBackButton: false as const,
currentStep: undefined,
totalSteps: undefined,
};
})()
: {
title: comm.confirmModal.title,
description: comm.confirmModal.description,
nextButtonText: comm.confirmModal.nextButtonText,
showBackButton: false as const,
currentStep: undefined,
totalSteps: undefined,
};
const modalConfig = (() => {
if (!pendingCardId) {
return {
title: comm.confirmModal.title,
description: comm.confirmModal.description,
nextButtonText: comm.confirmModal.nextButtonText,
showBackButton: false as const,
currentStep: undefined,
totalSteps: undefined,
};
}
if (pendingCardId in comm.modals) {
const modal = comm.modals[pendingCardId as keyof typeof comm.modals];
return {
title: modal.title,
description: modal.description,
nextButtonText: comm.addPlatform.nextButtonText,
showBackButton: false as const,
currentStep: undefined,
totalSteps: undefined,
};
}
const cardRow =
pendingCardId in comm.cards
? comm.cards[pendingCardId as keyof typeof comm.cards]
: null;
return {
title: cardRow?.label ?? comm.confirmModal.title,
description: cardRow?.supportText ?? comm.confirmModal.description,
nextButtonText: comm.addPlatform.nextButtonText,
showBackButton: false as const,
currentStep: undefined,
totalSteps: undefined,
};
})();
const handleCardClick = useCallback(
(id: string) => {
@@ -286,8 +252,9 @@ export function CommunicationMethodsScreen() {
showBackButton={modalConfig.showBackButton}
currentStep={modalConfig.currentStep}
totalSteps={modalConfig.totalSteps}
backdropVariant="loginYellow"
>
{isAddPlatformCard(pendingCardId) && pendingCardId ? (
{pendingCardId ? (
<AddPlatformModalContent
key={pendingCardId}
platformCardId={pendingCardId}