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:
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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user