diff --git a/app/create/CreateFlowLayoutClient.tsx b/app/create/CreateFlowLayoutClient.tsx index 2ee4581..fb83700 100644 --- a/app/create/CreateFlowLayoutClient.tsx +++ b/app/create/CreateFlowLayoutClient.tsx @@ -93,13 +93,16 @@ function CreateFlowLayoutContent({ const router = useRouter(); const pathname = usePathname(); const { openLogin } = useAuthModal(); + const skipCommunitySave = sessionResolved && Boolean(sessionUser); const { currentStep, nextStep, previousStep, goToNextStep, goToPreviousStep, - } = useCreateFlowNavigation(); + } = useCreateFlowNavigation( + skipCommunitySave ? { skipCommunitySave: true } : undefined, + ); const { state, clearState, updateState } = useCreateFlow(); const { draftSaveBannerMessage, setDraftSaveBannerMessage } = useCreateFlowDraftSaveBanner(); @@ -240,6 +243,16 @@ function CreateFlowLayoutContent({ await runAuthenticatedExit(opts); }; + useEffect(() => { + if ( + sessionResolved && + sessionUser && + currentStep === "community-save" + ) { + router.replace("/create/review"); + } + }, [sessionResolved, sessionUser, currentStep, router]); + useEffect(() => { if (currentStep !== "community-save") { setCommunitySaveMagicLinkError(null); diff --git a/app/create/hooks/useCreateFlowNavigation.ts b/app/create/hooks/useCreateFlowNavigation.ts index 74f5c4e..848e723 100644 --- a/app/create/hooks/useCreateFlowNavigation.ts +++ b/app/create/hooks/useCreateFlowNavigation.ts @@ -4,6 +4,7 @@ import { usePathname, useRouter } from "next/navigation"; import { useCallback } from "react"; import type { CreateFlowStep } from "../types"; import { + type CreateFlowNavigationOptions, getNextStep, getPreviousStep, parseCreateFlowScreenFromPathname, @@ -26,7 +27,9 @@ const blurActiveElement = (): void => { * * Resolves the active step from `/create/{screenId}` via {@link parseCreateFlowScreenFromPathname} (flowSteps). */ -export function useCreateFlowNavigation(): { +export function useCreateFlowNavigation( + options?: CreateFlowNavigationOptions, +): { currentStep: CreateFlowStep | null; goToNextStep: () => void; goToPreviousStep: () => void; @@ -41,8 +44,8 @@ export function useCreateFlowNavigation(): { const validStep = parseCreateFlowScreenFromPathname(pathname ?? null); - const nextStep = getNextStep(validStep); - const previousStep = getPreviousStep(validStep); + const nextStep = getNextStep(validStep, options); + const previousStep = getPreviousStep(validStep, options); const goToNextStep = useCallback(() => { blurActiveElement(); diff --git a/app/create/utils/flowSteps.ts b/app/create/utils/flowSteps.ts index b8138df..93f1331 100644 --- a/app/create/utils/flowSteps.ts +++ b/app/create/utils/flowSteps.ts @@ -37,16 +37,26 @@ export const VALID_STEPS: readonly CreateFlowStep[] = FLOW_STEP_ORDER; */ export const FIRST_STEP: CreateFlowStep = FLOW_STEP_ORDER[0]; +/** Options for navigation when the email / magic-link save step is not shown (signed-in users). */ +export type CreateFlowNavigationOptions = { + skipCommunitySave?: boolean; +}; + /** * Returns the next step in the flow, or null if current is last/invalid */ export function getNextStep( currentStep: CreateFlowStep | null | undefined, + options?: CreateFlowNavigationOptions, ): CreateFlowStep | null { if (!currentStep) return null; const index = FLOW_STEP_ORDER.indexOf(currentStep); if (index === -1 || index === FLOW_STEP_ORDER.length - 1) return null; - return FLOW_STEP_ORDER[index + 1] as CreateFlowStep; + const next = FLOW_STEP_ORDER[index + 1] as CreateFlowStep; + if (options?.skipCommunitySave && next === "community-save") { + return getNextStep("community-save", options); + } + return next; } /** @@ -54,11 +64,16 @@ export function getNextStep( */ export function getPreviousStep( currentStep: CreateFlowStep | null | undefined, + options?: CreateFlowNavigationOptions, ): CreateFlowStep | null { if (!currentStep) return null; const index = FLOW_STEP_ORDER.indexOf(currentStep); if (index <= 0) return null; - return FLOW_STEP_ORDER[index - 1] as CreateFlowStep; + const prev = FLOW_STEP_ORDER[index - 1] as CreateFlowStep; + if (options?.skipCommunitySave && prev === "community-save") { + return getPreviousStep("community-save", options); + } + return prev; } /** diff --git a/tests/unit/flowSteps.test.ts b/tests/unit/flowSteps.test.ts index 1cf4b9f..04e451c 100644 --- a/tests/unit/flowSteps.test.ts +++ b/tests/unit/flowSteps.test.ts @@ -55,4 +55,17 @@ describe("flowSteps", () => { expect(getNextStep("community-structure")).toBe("community-context"); expect(getNextStep("community-context")).toBe("community-size"); }); + + it("skipCommunitySave bridges upload → review and review → upload", () => { + const opts = { skipCommunitySave: true } as const; + expect(getNextStep("community-upload", opts)).toBe("review"); + expect(getPreviousStep("review", opts)).toBe("community-upload"); + }); + + it("skipCommunitySave does not change steps outside the save segment", () => { + const opts = { skipCommunitySave: true } as const; + expect(getNextStep("community-size", opts)).toBe("community-upload"); + expect(getNextStep("review", opts)).toBe("cards"); + expect(getPreviousStep("cards", opts)).toBe("review"); + }); });