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
+4 -1
View File
@@ -1,4 +1,5 @@
import type { CreateFlowState } from "../../app/create/types";
import { migrateLegacyCreateFlowState } from "./migrateLegacyCreateFlowState";
const jsonHeaders = { "Content-Type": "application/json" };
@@ -77,7 +78,9 @@ export async function fetchDraftFromServer(): Promise<CreateFlowState | null> {
if (!data.draft?.payload || typeof data.draft.payload !== "object") {
return null;
}
return data.draft.payload as CreateFlowState;
return migrateLegacyCreateFlowState(
data.draft.payload as Record<string, unknown>,
);
}
const DRAFT_SAVE_NETWORK_ERROR =
+1 -5
View File
@@ -59,11 +59,7 @@ export function buildPublishPayload(
return undefined;
};
let summary = firstNonEmpty(
state.summary,
state.communityContext,
state.communityReflection,
);
let summary = firstNonEmpty(state.summary, state.communityContext);
let sections = parseSectionsFromCreateFlowState(state);
if (sections.length === 0) {
+9
View File
@@ -0,0 +1,9 @@
const EMAIL_MAX_LEN = 254;
/** Pragmatic check for the create-flow “save progress” email field (draft + footer enablement). */
export function isValidCreateFlowSaveEmail(value: unknown): boolean {
if (typeof value !== "string") return false;
const t = value.trim();
if (t.length === 0 || t.length > EMAIL_MAX_LEN) return false;
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);
}
@@ -0,0 +1,25 @@
import type { CreateFlowState } from "../../app/create/types";
/**
* Maps pre-rename draft keys and step ids (`community-reflection` → `community-save`).
* Safe to run on any parsed draft payload before merging into context.
*/
export function migrateLegacyCreateFlowState(
raw: Record<string, unknown> | null | undefined,
): CreateFlowState {
if (!raw || typeof raw !== "object") return {};
const next: Record<string, unknown> = { ...raw };
if (typeof next.communityReflection === "string") {
if (
next.communitySaveEmail === undefined ||
next.communitySaveEmail === ""
) {
next.communitySaveEmail = next.communityReflection;
}
}
delete next.communityReflection;
if (next.currentStep === "community-reflection") {
next.currentStep = "community-save";
}
return next as CreateFlowState;
}
+24
View File
@@ -852,3 +852,27 @@ export type ButtonStateValue =
| "Active"
| "Hover"
| "Disabled";
/**
* ProportionBar layout variant (Figma uses a segmented track in the create-flow footer).
*/
export type ProportionBarVariantValue =
| "default"
| "segmented"
| "Default"
| "Segmented";
/**
* Normalize ProportionBar variant (Figma PascalCase vs codebase lowercase).
*/
export function normalizeProportionBarVariant(
value: string | undefined,
defaultValue: "default" | "segmented" = "default",
): "default" | "segmented" {
if (!value) return defaultValue;
const normalized = value.toLowerCase();
if (normalized === "default" || normalized === "segmented") {
return normalized;
}
return defaultValue;
}
+4 -3
View File
@@ -29,11 +29,12 @@ export const createFlowStateSchema = z
.object({
title: z.string().max(500).optional(),
summary: z.string().max(8000).optional(),
communityContext: z.string().max(8000).optional(),
communityReflection: z.string().max(8000).optional(),
communityContext: z.string().max(48).optional(),
communitySaveEmail: z.string().max(320).optional(),
selectedCommunitySizeIds: z.array(z.string()).optional(),
selectedOrganizationTypeIds: z.array(z.string()).optional(),
selectedGovernanceStyleIds: z.array(z.string()).optional(),
selectedScaleIds: z.array(z.string()).optional(),
selectedMaturityIds: z.array(z.string()).optional(),
currentStep: createFlowStepSchema.optional(),
sections: z.array(z.unknown()).optional(),
stakeholders: z.array(z.unknown()).optional(),