Create Community stage implemented

This commit is contained in:
adilallo
2026-04-14 09:22:03 -06:00
parent a0de78c020
commit f8255bc2c7
73 changed files with 1105 additions and 392 deletions
+14 -9
View File
@@ -33,26 +33,31 @@ export function CreateFlowScreenView({
maxLength={48}
/>
);
case "community-size":
return <CommunitySizeSelectScreen />;
case "community-structure":
return <CommunityStructureSelectScreen />;
case "community-context":
return (
<CreateFlowTextFieldScreen
messageNamespace="create.communityContext"
stateField="communityContext"
maxLength={2000}
maxLength={48}
mainAlign="center"
/>
);
case "community-structure":
return <CommunityStructureSelectScreen />;
case "community-size":
return <CommunitySizeSelectScreen />;
case "community-upload":
return <CommunityUploadScreen />;
case "community-reflection":
case "community-save":
return (
<CreateFlowTextFieldScreen
messageNamespace="create.communityReflection"
stateField="communityReflection"
maxLength={2000}
messageNamespace="create.communitySave"
stateField="communitySaveEmail"
maxLength={254}
mainAlign="center"
inputType="email"
showCharacterCount={false}
headerJustification="center"
/>
);
case "review":
+4 -3
View File
@@ -9,6 +9,7 @@ import CardStack from "../../../components/utility/CardStack";
import Create from "../../../components/modals/Create";
import TextArea from "../../../components/controls/TextArea";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
const IN_PERSON_CARD_ID = "in-person-meetings";
const SIGNAL_CARD_ID = "signal";
@@ -210,15 +211,15 @@ export function CardsScreen() {
variant="wideGridLoosePadding"
contentTopBelowMd="space-800"
>
<div className="flex w-full min-w-0 flex-col gap-6">
<div className="min-w-0">
<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="min-w-0 w-full">
<div className={CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}>
<CardStack
cards={sampleCards}
selectedIds={selectedIds}
@@ -9,6 +9,10 @@ import { parseDocumentSectionsForDisplay } from "../../../../lib/create/buildPub
import { readLastPublishedRule } from "../../../../lib/create/lastPublishedRule";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import {
CREATE_FLOW_MD_UP_GRID_CELL_CLASS,
CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS,
} from "../../components/createFlowLayoutTokens";
export function CompletedScreen() {
const mdUp = useCreateFlowMdUp();
@@ -67,8 +71,12 @@ export function CompletedScreen() {
return (
<>
<div className="flex min-h-0 w-full flex-1 flex-col overflow-hidden bg-[var(--color-teal-teal50,#c9fef9)] md:h-full">
<div className="mx-auto grid min-h-0 w-full max-w-[1280px] grid-cols-1 gap-4 px-5 max-md:max-w-[639px] max-md:pt-[var(--space-800)] max-md:pb-8 md:h-full md:grid-cols-2 md:gap-[var(--measures-spacing-1200,48px)] md:overflow-hidden md:px-12 md:py-0">
<div className="flex min-w-0 flex-col justify-start overflow-hidden md:justify-center md:pb-8">
<div
className={`mx-auto grid min-h-0 w-full grid-cols-1 gap-4 px-5 max-md:max-w-[639px] max-md:pt-[var(--space-800)] max-md:pb-8 md:h-full md:grid-cols-2 md:justify-items-center md:gap-[var(--measures-spacing-1200,48px)] md:overflow-hidden md:px-12 md:py-0 ${CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS}`}
>
<div
className={`flex flex-col justify-start overflow-hidden md:justify-center md:pb-8 ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<CreateFlowHeaderLockup
title={headerTitle}
description={headerDescription}
@@ -77,12 +85,14 @@ export function CompletedScreen() {
palette="inverse"
/>
</div>
<div className="scrollbar-hide relative flex min-h-0 min-w-0 flex-col overflow-x-hidden md:overflow-y-auto">
<div
className={`scrollbar-hide relative flex min-h-0 flex-col overflow-x-hidden md:overflow-y-auto ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<div
className="pointer-events-none sticky top-0 z-10 hidden h-5 shrink-0 bg-gradient-to-b from-[var(--color-teal-teal50,#c9fef9)]/55 from-0% via-[var(--color-teal-teal50,#c9fef9)]/20 via-50% to-transparent md:block"
aria-hidden
/>
<div className="min-w-0 py-0 md:pb-8">
<div className="w-full min-w-0 py-0 md:pb-8">
<CommunityRuleDocument
sections={documentSections}
useCardStyle={!mdUp}
@@ -1,40 +1,63 @@
"use client";
import type { ReactNode } from "react";
import NumberedList from "../../../components/type/NumberedList";
import { useTranslation } from "../../../contexts/MessagesContext";
import { useMessages } from "../../../contexts/MessagesContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
/** Create Community — frame 1 (Figma 20094-16005). */
/**
* Create Community — frame 1 (Figma [20094-16005](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=20094-16005)).
* URL: /create/informational
*/
export function InformationalScreen() {
const mdUp = useCreateFlowMdUp();
const t = useTranslation("create.informational");
const copy = useMessages().create.informational;
const items = [
{
title: t("steps.0.title"),
description: t("steps.0.description"),
title: copy.steps["0"].title,
description: copy.steps["0"].description,
},
{
title: t("steps.1.title"),
description: t("steps.1.description"),
title: copy.steps["1"].title,
description: copy.steps["1"].description,
},
{
title: t("steps.2.title"),
description: t("steps.2.description"),
title: copy.steps["2"].title,
description: copy.steps["2"].description,
},
];
const description: ReactNode = (
<>
{copy.descriptionLead}{" "}
<a
href="#"
className="font-inter font-normal text-[var(--color-content-default-tertiary,#b4b4b4)] underline decoration-solid underline-offset-[3px] cursor-pointer"
onClick={(e) => {
e.preventDefault();
}}
>
{copy.workshopLabel}
</a>{" "}
{copy.descriptionTrail}
</>
);
return (
<CreateFlowStepShell
variant="centeredNarrow"
contentTopBelowMd="space-1400"
>
<div className="flex w-full max-w-[640px] flex-col items-center gap-12">
<div
className={`flex flex-col items-center gap-[var(--measures-spacing-1200,48px)] ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<CreateFlowHeaderLockup
title={t("title")}
description={t("description")}
title={copy.title}
description={description}
justification="left"
/>
<NumberedList items={items} size={mdUp ? "M" : "S"} />
@@ -3,37 +3,56 @@
import RuleCard from "../../../components/cards/RuleCard";
import { useTranslation } from "../../../contexts/MessagesContext";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowLgUp } from "../../hooks/useCreateFlowLgUp";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import {
CREATE_FLOW_MD_UP_GRID_CELL_CLASS,
CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS,
} from "../../components/createFlowLayoutTokens";
/** Create Community — frame 8 (Figma 19706-12135); URL segment `review`. */
/** Create Community review — Figma `19706:12135` (`/create/review`; two columns from `lg:`; column caps in `createFlowLayoutTokens`). */
export function CommunityReviewScreen() {
const mdUp = useCreateFlowMdUp();
const lgUp = useCreateFlowLgUp();
const t = useTranslation("create.review");
const { state } = useCreateFlow();
const cardTitle =
typeof state.title === "string" && state.title.trim().length > 0
? state.title.trim()
: t("ruleCard.title");
const cardDescription =
typeof state.communityContext === "string" &&
state.communityContext.trim().length > 0
? state.communityContext.trim()
: t("ruleCard.description");
return (
<CreateFlowStepShell
variant="wideGridLoosePadding"
contentTopBelowMd="space-1400"
>
<div className="flex w-full min-w-0 flex-col gap-4 md:grid md:grid-cols-2 md:gap-[var(--measures-spacing-1200,48px)]">
<div className="min-w-0">
<div
className={`flex w-full min-w-0 flex-col items-center gap-6 lg:mx-auto lg:w-full lg:grid lg:grid-cols-2 lg:items-center lg:justify-items-center lg:gap-x-[var(--measures-spacing-1200,48px)] lg:gap-y-6 ${CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS}`}
>
<div
className={`flex flex-col justify-center lg:min-h-[212px] ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<CreateFlowHeaderLockup
title={t("header.title")}
description={t("header.description")}
justification="left"
/>
</div>
<div className="min-w-0 w-full">
<div className={CREATE_FLOW_MD_UP_GRID_CELL_CLASS}>
<RuleCard
title={t("ruleCard.title")}
description={t("ruleCard.description")}
size={mdUp ? "L" : "M"}
title={cardTitle}
description={cardDescription}
size={lgUp ? "L" : "M"}
expanded={false}
backgroundColor="bg-[#c9fef9]"
backgroundColor="bg-[var(--color-teal-teal50,#c9fef9)]"
logoUrl="/assets/Vector_MutualAid.svg"
logoAlt={t("ruleCard.logoAlt")}
className="rounded-[16px]"
logoAlt={cardTitle}
className="rounded-[24px]"
/>
</div>
</div>
@@ -8,6 +8,10 @@ import type { CardStackItem } from "../../../components/utility/CardStack/CardSt
import { useMessages } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import {
CREATE_FLOW_MD_UP_GRID_CELL_CLASS,
CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS,
} from "../../components/createFlowLayoutTokens";
export function RightRailScreen() {
const m = useMessages();
@@ -76,8 +80,12 @@ export function RightRailScreen() {
return (
<div className="flex h-full min-h-0 w-full flex-1 flex-col overflow-hidden md:h-full">
<div className="flex min-h-0 flex-1 overflow-hidden px-5 max-md:overflow-y-auto md:px-12">
<div className="mx-auto grid h-auto min-h-0 w-full max-w-[1280px] shrink-0 grid-cols-1 gap-6 min-w-0 max-md:pt-[var(--space-800)] max-md:pb-8 md:h-full md:grid-cols-2 md:gap-12 md:pb-8">
<div className="flex min-w-0 flex-col items-stretch justify-start overflow-hidden md:justify-center">
<div
className={`mx-auto grid h-auto min-h-0 w-full shrink-0 grid-cols-1 gap-6 min-w-0 max-md:pt-[var(--space-800)] max-md:pb-8 md:h-full md:grid-cols-2 md:justify-items-center md:gap-12 md:pb-8 ${CREATE_FLOW_TWO_COLUMN_MAX_WIDTH_CLASS}`}
>
<div
className={`flex flex-col items-stretch justify-start overflow-hidden md:justify-center ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<DecisionMakingSidebar
title={rr.sidebar.title}
description={sidebarDescription}
@@ -89,8 +97,10 @@ export function RightRailScreen() {
justification={mdUp ? "left" : "center"}
/>
</div>
<div className="scrollbar-hide relative flex min-h-0 min-w-0 flex-col overflow-x-hidden max-md:overflow-visible md:overflow-y-auto">
<div className="flex min-w-0 flex-col items-center gap-6 py-0 md:pb-8">
<div
className={`scrollbar-hide relative flex min-h-0 flex-col overflow-x-hidden max-md:overflow-visible md:overflow-y-auto ${CREATE_FLOW_MD_UP_GRID_CELL_CLASS}`}
>
<div className="flex w-full min-w-0 flex-col items-center gap-6 py-0 md:pb-8">
<CardStack
cards={sampleCards}
selectedIds={selectedIds}
@@ -1,44 +1,13 @@
"use client";
import { useState, useMemo, useEffect, type Dispatch, type SetStateAction } from "react";
import { useState, useEffect } from "react";
import MultiSelect from "../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../components/controls/MultiSelect/MultiSelect.types";
import { useMessages, useTranslation } from "../../../contexts/MessagesContext";
import { useMessages } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
function createListCustomHandlers(
setList: Dispatch<SetStateAction<ChipOption[]>>,
confirmState: "Unselected" | "Selected",
onInteraction?: () => void,
) {
const touch = () => onInteraction?.();
return {
onAddClick: () => {
touch();
setList((prev) => [
...prev,
{ id: crypto.randomUUID(), label: "", state: "Custom" },
]);
},
onCustomChipConfirm: (chipId: string, value: string) => {
touch();
setList((prev) =>
prev.map((opt) =>
opt.id === chipId
? { ...opt, label: value, state: confirmState }
: opt,
),
);
},
onCustomChipClose: (chipId: string) => {
touch();
setList((prev) => prev.filter((o) => o.id !== chipId));
},
};
}
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
function chipRowsFromLabels(
rows: readonly { label: string }[],
@@ -56,17 +25,16 @@ function selectedIdsFromOptions(options: ChipOption[]): string[] {
.map((o) => o.id);
}
/** Create Community — frame 3 (Figma 20094-18244). */
/** Create Community — Figma `20094:41317`, chips only (layout tokens shared with structure select). */
export function CommunitySizeSelectScreen() {
const m = useMessages();
const cs = m.create.communitySize;
const { markCreateFlowInteraction, updateState, state } = useCreateFlow();
const mdUp = useCreateFlowMdUp();
const t = useTranslation("create.communitySize");
const [communitySizeOptions, setCommunitySizeOptions] = useState<
ChipOption[]
>(() => {
const base = chipRowsFromLabels(m.create.communitySize.communitySizes);
const base = chipRowsFromLabels(cs.communitySizes);
const selected = new Set(state.selectedCommunitySizeIds ?? []);
return base.map((opt) => ({
...opt,
@@ -90,16 +58,6 @@ export function CommunitySizeSelectScreen() {
);
}, [state.selectedCommunitySizeIds]);
const communityCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setCommunitySizeOptions,
"Unselected",
markCreateFlowInteraction,
),
[markCreateFlowInteraction],
);
const persistSelection = (next: ChipOption[]) => {
markCreateFlowInteraction();
setCommunitySizeOptions(next);
@@ -123,18 +81,13 @@ export function CommunitySizeSelectScreen() {
persistSelection(next);
};
const multiLabel = t("multiSelect.label");
const addText = t("multiSelect.addButtonText");
const multiSelectBlock = (
<MultiSelect
label={multiLabel}
size="S"
formHeader={false}
size="M"
options={communitySizeOptions}
onChipClick={handleCommunitySizeClick}
{...communityCustomHandlers}
addButton={true}
addButtonText={addText}
addButton={false}
/>
);
@@ -143,29 +96,22 @@ export function CommunitySizeSelectScreen() {
variant="centeredNarrow"
contentTopBelowMd="space-1400"
>
{mdUp ? (
<div className="flex w-full max-w-[1280px] items-center justify-center gap-[var(--measures-spacing-1200,48px)]">
<div className="flex max-w-[640px] min-h-px min-w-px flex-[1_0_0] flex-col items-start justify-center gap-[var(--measures-spacing-200,8px)] py-[12px]">
<CreateFlowHeaderLockup
title={t("header.title")}
description={t("header.description")}
justification="left"
/>
</div>
<div className="flex max-w-[640px] min-h-px min-w-px flex-[1_0_0] flex-col items-start gap-[var(--measures-spacing-800,32px)]">
{multiSelectBlock}
</div>
</div>
) : (
<div className="flex w-full max-w-[640px] flex-col items-start gap-[var(--measures-spacing-400,16px)]">
<div className="flex w-full min-w-0 flex-col items-start gap-[var(--measures-spacing-400,16px)] md:max-w-[640px] lg:max-w-[1328px] lg:flex-row lg:flex-nowrap lg:items-center lg:justify-center lg:gap-[var(--measures-spacing-1200,48px)]">
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-200,8px)] lg:flex-1 lg:justify-center lg:py-[12px] ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<CreateFlowHeaderLockup
title={t("header.title")}
description={t("header.description")}
title={cs.header.title}
description={cs.header.description}
justification="left"
/>
</div>
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-800,32px)] lg:flex-1 ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
{multiSelectBlock}
</div>
)}
</div>
</CreateFlowStepShell>
);
}
@@ -9,11 +9,11 @@ import {
} from "react";
import MultiSelect from "../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../components/controls/MultiSelect/MultiSelect.types";
import { useMessages, useTranslation } from "../../../contexts/MessagesContext";
import { useMessages } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
function createListCustomHandlers(
setList: Dispatch<SetStateAction<ChipOption[]>>,
@@ -73,28 +73,38 @@ function applySavedSelection(
);
}
/** Create Community — frame 5 (Figma 20094-41317). */
function selectedIdsFromOptions(options: ChipOption[]): string[] {
return options
.filter((o) => o.state === "Selected")
.map((o) => o.id);
}
/** Create Community step 3 — Figma `20094:18244` (responsive grid + column caps via `createFlowLayoutTokens`). */
export function CommunityStructureSelectScreen() {
const m = useMessages();
const cs = m.create.communityStructure;
const { markCreateFlowInteraction, updateState, state } = useCreateFlow();
const mdUp = useCreateFlowMdUp();
const t = useTranslation("create.communityStructure");
const [organizationTypeOptions, setOrganizationTypeOptions] = useState<
ChipOption[]
>(() =>
applySavedSelection(
chipRowsFromLabels(m.create.communityStructure.organizationTypes),
chipRowsFromLabels(cs.organizationTypes),
state.selectedOrganizationTypeIds,
),
);
const [governanceStyleOptions, setGovernanceStyleOptions] = useState<
ChipOption[]
>(() =>
const [scaleOptions, setScaleOptions] = useState<ChipOption[]>(() =>
applySavedSelection(
chipRowsFromLabels(m.create.communityStructure.governanceStyles),
state.selectedGovernanceStyleIds,
chipRowsFromLabels(cs.scaleOptions),
state.selectedScaleIds,
),
);
const [maturityOptions, setMaturityOptions] = useState<ChipOption[]>(() =>
applySavedSelection(
chipRowsFromLabels(cs.maturityOptions),
state.selectedMaturityIds,
),
);
@@ -105,10 +115,14 @@ export function CommunityStructureSelectScreen() {
}, [state.selectedOrganizationTypeIds]);
useEffect(() => {
setGovernanceStyleOptions((prev) =>
applySavedSelection(prev, state.selectedGovernanceStyleIds),
setScaleOptions((prev) => applySavedSelection(prev, state.selectedScaleIds));
}, [state.selectedScaleIds]);
useEffect(() => {
setMaturityOptions((prev) =>
applySavedSelection(prev, state.selectedMaturityIds),
);
}, [state.selectedGovernanceStyleIds]);
}, [state.selectedMaturityIds]);
const organizationCustomHandlers = useMemo(
() =>
@@ -119,10 +133,19 @@ export function CommunityStructureSelectScreen() {
),
[markCreateFlowInteraction],
);
const governanceCustomHandlers = useMemo(
const scaleCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setGovernanceStyleOptions,
setScaleOptions,
"Unselected",
markCreateFlowInteraction,
),
[markCreateFlowInteraction],
);
const maturityCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setMaturityOptions,
"Unselected",
markCreateFlowInteraction,
),
@@ -132,75 +155,100 @@ export function CommunityStructureSelectScreen() {
const persistOrg = (next: ChipOption[]) => {
markCreateFlowInteraction();
setOrganizationTypeOptions(next);
updateState({
selectedOrganizationTypeIds: next
.filter((o) => o.state === "Selected")
.map((o) => o.id),
});
updateState({ selectedOrganizationTypeIds: selectedIdsFromOptions(next) });
};
const persistGov = (next: ChipOption[]) => {
const persistScale = (next: ChipOption[]) => {
markCreateFlowInteraction();
setGovernanceStyleOptions(next);
updateState({
selectedGovernanceStyleIds: next
.filter((o) => o.state === "Selected")
.map((o) => o.id),
});
setScaleOptions(next);
updateState({ selectedScaleIds: selectedIdsFromOptions(next) });
};
const persistMaturity = (next: ChipOption[]) => {
markCreateFlowInteraction();
setMaturityOptions(next);
updateState({ selectedMaturityIds: selectedIdsFromOptions(next) });
};
const handleOrganizationTypeClick = (chipId: string) => {
const next: ChipOption[] = organizationTypeOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "Selected"
? ("Unselected" as const)
: ("Selected" as const),
}
: opt,
persistOrg(
organizationTypeOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "Selected"
? ("Unselected" as const)
: ("Selected" as const),
}
: opt,
),
);
persistOrg(next);
};
const handleGovernanceStyleClick = (chipId: string) => {
const next: ChipOption[] = governanceStyleOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "Selected"
? ("Unselected" as const)
: ("Selected" as const),
}
: opt,
const handleScaleClick = (chipId: string) => {
persistScale(
scaleOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "Selected"
? ("Unselected" as const)
: ("Selected" as const),
}
: opt,
),
);
persistGov(next);
};
const multiLabel = t("multiSelect.label");
const addText = t("multiSelect.addButtonText");
const handleMaturityClick = (chipId: string) => {
persistMaturity(
maturityOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "Selected"
? ("Unselected" as const)
: ("Selected" as const),
}
: opt,
),
);
};
const multiSelectBlock = (
<>
<MultiSelect
label={multiLabel}
label={cs.organizationMultiSelect.label}
showHelpIcon
size="S"
options={organizationTypeOptions}
onChipClick={handleOrganizationTypeClick}
{...organizationCustomHandlers}
addButton={true}
addButtonText={addText}
addButton
addButtonText={cs.organizationMultiSelect.addButtonText}
/>
<MultiSelect
label={multiLabel}
label={cs.scaleMultiSelect.label}
showHelpIcon
size="S"
options={governanceStyleOptions}
onChipClick={handleGovernanceStyleClick}
{...governanceCustomHandlers}
addButton={true}
addButtonText={addText}
options={scaleOptions}
onChipClick={handleScaleClick}
{...scaleCustomHandlers}
addButton
addButtonText={cs.scaleMultiSelect.addButtonText}
/>
<MultiSelect
label={cs.maturityMultiSelect.label}
showHelpIcon
size="S"
options={maturityOptions}
onChipClick={handleMaturityClick}
{...maturityCustomHandlers}
addButton
addButtonText={cs.maturityMultiSelect.addButtonText}
/>
</>
);
@@ -210,29 +258,22 @@ export function CommunityStructureSelectScreen() {
variant="centeredNarrow"
contentTopBelowMd="space-1400"
>
{mdUp ? (
<div className="flex w-full max-w-[1280px] items-center justify-center gap-[var(--measures-spacing-1200,48px)]">
<div className="flex max-w-[640px] min-h-px min-w-px flex-[1_0_0] flex-col items-start justify-center gap-[var(--measures-spacing-200,8px)] py-[12px]">
<CreateFlowHeaderLockup
title={t("header.title")}
description={t("header.description")}
justification="left"
/>
</div>
<div className="flex max-w-[640px] min-h-px min-w-px flex-[1_0_0] flex-col items-start gap-[var(--measures-spacing-800,32px)]">
{multiSelectBlock}
</div>
</div>
) : (
<div className="flex w-full max-w-[640px] flex-col items-start gap-[var(--measures-spacing-400,16px)]">
<div className="flex w-full min-w-0 flex-col items-start gap-[var(--measures-spacing-400,16px)] md:max-w-[640px] lg:max-w-[1328px] lg:flex-row lg:flex-nowrap lg:items-center lg:justify-center lg:gap-[var(--measures-spacing-1200,48px)]">
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-200,8px)] lg:flex-1 lg:justify-center lg:py-[12px] ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<CreateFlowHeaderLockup
title={t("header.title")}
description={t("header.description")}
title={cs.header.title}
description={cs.header.description}
justification="left"
/>
</div>
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-800,32px)] lg:flex-1 ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
{multiSelectBlock}
</div>
)}
</div>
</CreateFlowStepShell>
);
}
@@ -8,6 +8,7 @@ import { useTranslation } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
export function ConfirmStakeholdersScreen() {
const { markCreateFlowInteraction } = useCreateFlow();
@@ -50,7 +51,9 @@ export function ConfirmStakeholdersScreen() {
variant="centeredNarrowBottomPad"
contentTopBelowMd="space-1400"
>
<div className="flex w-full max-w-[640px] flex-col items-start gap-[var(--measures-spacing-300,12px)]">
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-300,12px)] ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<div className="flex w-full flex-col gap-[var(--measures-spacing-200,8px)] py-[12px]">
<CreateFlowHeaderLockup
title={t("title")}
@@ -1,18 +1,30 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, type HTMLInputTypeAttribute } from "react";
import TextInput from "../../../components/controls/TextInput";
import type { HeaderLockupJustificationValue } from "../../../components/type/HeaderLockup/HeaderLockup.types";
import { useTranslation } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import {
CreateFlowStepShell,
type CreateFlowContentTopBelowMd,
} from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
import type { CreateFlowTextStateField } from "../../types";
type Props = {
messageNamespace: string;
stateField: CreateFlowTextStateField;
maxLength: number;
/** Figma Flow — Text (`20094:41243`): main column `items-center` + horizontal padding token. */
mainAlign?: "start" | "center";
inputType?: HTMLInputTypeAttribute;
showCharacterCount?: boolean;
headerJustification?: HeaderLockupJustificationValue;
/** Top spacing under top chrome (`CreateFlowStepShell` / `CreateFlowContentTopBelowMd`). */
contentTopBelowMd?: CreateFlowContentTopBelowMd;
};
/**
@@ -22,6 +34,11 @@ export function CreateFlowTextFieldScreen({
messageNamespace,
stateField,
maxLength,
mainAlign = "start",
inputType = "text",
showCharacterCount = true,
headerJustification = "left",
contentTopBelowMd = "space-1400",
}: Props) {
const { markCreateFlowInteraction, updateState, state } = useCreateFlow();
const mdUp = useCreateFlowMdUp();
@@ -42,20 +59,35 @@ export function CreateFlowTextFieldScreen({
}, [state, stateField]);
const characterCount = value.length;
const hint = t("characterCountTemplate")
.replace("{current}", String(characterCount))
.replace("{max}", String(maxLength));
const hint =
showCharacterCount === false
? false
: t("characterCountTemplate")
.replace("{current}", String(characterCount))
.replace("{max}", String(maxLength));
const mainItems =
mainAlign === "center" ? "items-center" : "items-start";
return (
<CreateFlowStepShell variant="centeredNarrow">
<div className="flex w-full max-w-[640px] flex-col items-start gap-[18px]">
<CreateFlowHeaderLockup
title={t("title")}
description={t("description")}
justification="left"
/>
<CreateFlowStepShell
variant="centeredNarrow"
contentTopBelowMd={contentTopBelowMd}
>
<div
className={`flex flex-col gap-[18px] ${mainItems} ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<div className="w-full">
<CreateFlowHeaderLockup
title={t("title")}
description={t("description")}
justification={headerJustification}
/>
</div>
<div className="w-full">
<TextInput
className="!transition-none"
type={inputType}
placeholder={t("placeholder")}
value={value}
onChange={(e) => {
@@ -1,17 +1,17 @@
"use client";
import Upload from "../../../components/controls/Upload";
import { useTranslation } from "../../../contexts/MessagesContext";
import { useMessages } from "../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowMdUp } from "../../hooks/useCreateFlowMdUp";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowStepShell } from "../../components/CreateFlowStepShell";
import { CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS } from "../../components/createFlowLayoutTokens";
/** Create Community — frame 6 (Figma 20094-41524). */
/** Create Community — Figma Flow — Upload `20094:41524`. */
export function CommunityUploadScreen() {
const m = useMessages();
const u = m.create.communityUpload;
const { markCreateFlowInteraction } = useCreateFlow();
const mdUp = useCreateFlowMdUp();
const t = useTranslation("create.communityUpload");
const handleUploadClick = () => {
markCreateFlowInteraction();
@@ -22,16 +22,21 @@ export function CommunityUploadScreen() {
variant="centeredNarrow"
contentTopBelowMd="space-1400"
>
<div className="flex w-full max-w-[640px] flex-col items-center gap-[18px]">
<CreateFlowHeaderLockup
title={t("title")}
description={t("description")}
justification={mdUp ? "center" : "left"}
/>
<div className="w-full max-w-[474px]">
<div
className={`flex flex-col items-center gap-[18px] ${CREATE_FLOW_MD_UP_COLUMN_MAX_CLASS}`}
>
<div className="w-full">
<CreateFlowHeaderLockup
title={u.title}
description={u.description}
justification="center"
/>
</div>
<div className="w-full">
<Upload
active={true}
showHelpIcon={true}
showHelpIcon={false}
hintText={u.hintText}
onClick={handleUploadClick}
/>
</div>