Walk Create Community through the Figma screens and restore a chosen logo after reload, so a guest can leave without saving until they reach the email step.

This commit is contained in:
adilallo committed 2026-11-05 16:14:04 -07:00
1 parent ca1f58a50c
commit 2348a9e94f
61 files changed
+1110 -421

No files matched your search

@@ -5,6 +5,7 @@ import MultiSelect from "../../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../../components/controls/MultiSelect/MultiSelect.types";
import { useMessages } from "../../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowContinueAttempt } from "../../context/CreateFlowContinueAttemptContext";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowTwoColumnSelectShell } from "../../components/CreateFlowTwoColumnSelectShell";
@@ -48,6 +49,7 @@ export function CommunitySizeSelectScreen() {
const m = useMessages();
const cs = m.create.community.communitySize;
const { markCreateFlowInteraction, updateState, state } = useCreateFlow();
const { attempted } = useCreateFlowContinueAttempt();
const [communitySizeOptions, setCommunitySizeOptions] = useState<
ChipOption[]
@@ -87,6 +89,9 @@ export function CommunitySizeSelectScreen() {
persistSelection(withSoleSelection(communitySizeOptions, nextId));
};
const showSizeError =
attempted && soleSizeId(state.selectedCommunitySizeIds) == null;
const multiSelectBlock = (
<MultiSelect
formHeader={false}
@@ -94,6 +99,7 @@ export function CommunitySizeSelectScreen() {
options={communitySizeOptions}
onChipClick={handleCommunitySizeClick}
addButton={false}
errorMessage={showSizeError ? cs.pickOneError : undefined}
/>
);
@@ -11,6 +11,7 @@ import MultiSelect from "../../../../components/controls/MultiSelect";
import type { ChipOption } from "../../../../components/controls/MultiSelect/MultiSelect.types";
import { useMessages } from "../../../../contexts/MessagesContext";
import { useCreateFlow } from "../../context/CreateFlowContext";
import { useCreateFlowContinueAttempt } from "../../context/CreateFlowContinueAttemptContext";
import type { CommunityStructureChipSnapshotRow } from "../../types";
import { CreateFlowHeaderLockup } from "../../components/CreateFlowHeaderLockup";
import { CreateFlowTwoColumnSelectShell } from "../../components/CreateFlowTwoColumnSelectShell";
@@ -73,10 +74,29 @@ function applySavedSelection(
);
}
function withSoleSelection(
options: ChipOption[],
selectedId: string | null,
): ChipOption[] {
return options.map((opt) =>
opt.state === "custom"
? opt
: {
...opt,
state:
opt.id === selectedId
? ("selected" as const)
: ("unselected" as const),
},
);
}
function selectedIdsFromOptions(options: ChipOption[]): string[] {
return options
.filter((o) => o.state === "selected")
.map((o) => o.id);
return options.filter((o) => o.state === "selected").map((o) => o.id);
}
function firstSelectedId(options: ChipOption[]): string | null {
return selectedIdsFromOptions(options)[0] ?? null;
}
function chipOptionsToSnapshotRows(
@@ -103,22 +123,46 @@ function snapshotRowsToChipOptions(
}));
}
/** Create Community step 3 — Figma `20094:18244` (responsive grid + column caps via `createFlowLayoutTokens`). */
function organizationIdsForPersist(
mainId: string | null,
otherIds: readonly string[],
): string[] {
if (!mainId) return [];
return [mainId, ...otherIds.filter((id) => id !== mainId)];
}
/** Create Community type step — Figma `25224:105767`. */
export function CommunityStructureSelectScreen() {
const m = useMessages();
const cs = m.create.community.communityStructure;
const { markCreateFlowInteraction, updateState, state } = useCreateFlow();
const { attempted } = useCreateFlowContinueAttempt();
const [organizationTypeOptions, setOrganizationTypeOptions] = useState<
ChipOption[]
>(() => {
const savedKindIds = state.selectedOrganizationTypeIds ?? [];
const savedMainIndex = savedKindIds.findIndex((id) => id.length > 0);
const savedMainId =
savedMainIndex >= 0 ? savedKindIds[savedMainIndex]! : null;
const savedOtherIds =
savedMainIndex >= 0 ? savedKindIds.slice(savedMainIndex + 1) : [];
const [mainKindOptions, setMainKindOptions] = useState<ChipOption[]>(() => {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.organizationTypes,
);
return withSoleSelection(
fromSnap ?? chipRowsFromLabels(cs.organizationTypes),
savedMainId,
);
});
const [otherKindOptions, setOtherKindOptions] = useState<ChipOption[]>(() => {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.otherOrganizationTypes,
);
if (fromSnap) return fromSnap;
return applySavedSelection(
chipRowsFromLabels(cs.organizationTypes),
state.selectedOrganizationTypeIds,
savedOtherIds,
);
});
@@ -137,29 +181,48 @@ export function CommunityStructureSelectScreen() {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.maturity,
);
if (fromSnap) return fromSnap;
return applySavedSelection(
chipRowsFromLabels(cs.maturityOptions),
state.selectedMaturityIds,
);
const base = fromSnap ?? chipRowsFromLabels(cs.maturityOptions);
const maturityId =
(state.selectedMaturityIds ?? []).find((id) => id.length > 0) ?? null;
return withSoleSelection(base, maturityId);
});
useEffect(() => {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.organizationTypes,
);
if (fromSnap) {
setOrganizationTypeOptions(fromSnap);
return;
}
setOrganizationTypeOptions((prev) =>
applySavedSelection(prev, state.selectedOrganizationTypeIds),
const mainId =
(state.selectedOrganizationTypeIds ?? []).find((id) => id.length > 0) ??
null;
setMainKindOptions(
withSoleSelection(
fromSnap ?? chipRowsFromLabels(cs.organizationTypes),
mainId,
),
);
}, [
cs.organizationTypes,
state.communityStructureChipSnapshots?.organizationTypes,
state.selectedOrganizationTypeIds,
]);
useEffect(() => {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.otherOrganizationTypes,
);
const ids = state.selectedOrganizationTypeIds ?? [];
const mainId = ids.find((id) => id.length > 0);
const otherIds = mainId ? ids.slice(ids.indexOf(mainId) + 1) : [];
if (fromSnap) {
setOtherKindOptions(fromSnap);
return;
}
setOtherKindOptions((prev) => applySavedSelection(prev, otherIds));
}, [
state.communityStructureChipSnapshots?.otherOrganizationTypes,
state.selectedOrganizationTypeIds,
]);
useEffect(() => {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.scale,
@@ -178,53 +241,50 @@ export function CommunityStructureSelectScreen() {
const fromSnap = snapshotRowsToChipOptions(
state.communityStructureChipSnapshots?.maturity,
);
const maturityId =
(state.selectedMaturityIds ?? []).find((id) => id.length > 0) ?? null;
if (fromSnap) {
setMaturityOptions(fromSnap);
setMaturityOptions(withSoleSelection(fromSnap, maturityId));
return;
}
setMaturityOptions((prev) =>
applySavedSelection(prev, state.selectedMaturityIds),
);
setMaturityOptions((prev) => withSoleSelection(prev, maturityId));
}, [
state.communityStructureChipSnapshots?.maturity,
state.selectedMaturityIds,
]);
const organizationCustomHandlers = useMemo(
const mainKindCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setOrganizationTypeOptions,
setMainKindOptions,
"unselected",
markCreateFlowInteraction,
),
[markCreateFlowInteraction],
);
const scaleCustomHandlers = useMemo(
const otherKindCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setScaleOptions,
"unselected",
markCreateFlowInteraction,
),
[markCreateFlowInteraction],
);
const maturityCustomHandlers = useMemo(
() =>
createListCustomHandlers(
setMaturityOptions,
setOtherKindOptions,
"unselected",
markCreateFlowInteraction,
),
[markCreateFlowInteraction],
);
const persistOrg = (next: ChipOption[]) => {
const persistKinds = (main: ChipOption[], others: ChipOption[]) => {
markCreateFlowInteraction();
setOrganizationTypeOptions(next);
setMainKindOptions(main);
setOtherKindOptions(others);
const mainId = firstSelectedId(main);
updateState({
selectedOrganizationTypeIds: selectedIdsFromOptions(next),
selectedOrganizationTypeIds: organizationIdsForPersist(
mainId,
selectedIdsFromOptions(others),
),
communityStructureChipSnapshots: {
organizationTypes: chipOptionsToSnapshotRows(next),
organizationTypes: chipOptionsToSnapshotRows(main),
otherOrganizationTypes: chipOptionsToSnapshotRows(others),
},
});
};
@@ -251,9 +311,16 @@ export function CommunityStructureSelectScreen() {
});
};
const handleOrganizationTypeClick = (chipId: string) => {
persistOrg(
organizationTypeOptions.map((opt) =>
const handleMainKindClick = (chipId: string) => {
const current = firstSelectedId(mainKindOptions);
const nextId = current === chipId ? null : chipId;
persistKinds(withSoleSelection(mainKindOptions, nextId), otherKindOptions);
};
const handleOtherKindClick = (chipId: string) => {
persistKinds(
mainKindOptions,
otherKindOptions.map((opt) =>
opt.id === chipId
? {
...opt,
@@ -284,49 +351,49 @@ export function CommunityStructureSelectScreen() {
};
const handleMaturityClick = (chipId: string) => {
persistMaturity(
maturityOptions.map((opt) =>
opt.id === chipId
? {
...opt,
state:
opt.state === "selected"
? ("unselected" as const)
: ("selected" as const),
}
: opt,
),
);
const current = firstSelectedId(maturityOptions);
const nextId = current === chipId ? null : chipId;
persistMaturity(withSoleSelection(maturityOptions, nextId));
};
const showMainError = attempted && firstSelectedId(mainKindOptions) == null;
const showMaturityError =
attempted && firstSelectedId(maturityOptions) == null;
const multiSelectBlock = (
<>
<MultiSelect
label={cs.organizationMultiSelect.label}
label={cs.mainKindMultiSelect.label}
helperText={cs.mainKindMultiSelect.helperText}
size="s"
options={organizationTypeOptions}
onChipClick={handleOrganizationTypeClick}
{...organizationCustomHandlers}
options={mainKindOptions}
onChipClick={handleMainKindClick}
{...mainKindCustomHandlers}
addButton
errorMessage={showMainError ? cs.pickOneError : undefined}
/>
<MultiSelect
label={cs.otherKindMultiSelect.label}
size="s"
options={otherKindOptions}
onChipClick={handleOtherKindClick}
{...otherKindCustomHandlers}
addButton
addButtonText={cs.organizationMultiSelect.addButtonText}
/>
<MultiSelect
label={cs.scaleMultiSelect.label}
size="s"
options={scaleOptions}
onChipClick={handleScaleClick}
{...scaleCustomHandlers}
addButton
addButtonText={cs.scaleMultiSelect.addButtonText}
addButton={false}
/>
<MultiSelect
label={cs.maturityMultiSelect.label}
size="s"
options={maturityOptions}
onChipClick={handleMaturityClick}
{...maturityCustomHandlers}
addButton
addButtonText={cs.maturityMultiSelect.addButtonText}
addButton={false}
errorMessage={showMaturityError ? cs.pickOneError : undefined}
/>
</>
);