From da259509886a4ac34443eebb020c7cdf5789024d Mon Sep 17 00:00:00 2001 From: Moheeb Zara Date: Sat, 16 May 2026 16:29:32 -0700 Subject: [PATCH] harden(forms): prevent duplicate onboarding form submission on Back/Forward Phase 4 self-audit: alreadySubmitted was a page-load snapshot, so a member who submitted a form/waiver step then navigated Back and Forward would insert a second submission. Track submitted steps in session state and treat them as already-submitted. --- app/onboarding/onboarding-flow.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/onboarding/onboarding-flow.tsx b/app/onboarding/onboarding-flow.tsx index 7aca9a1..faa6f52 100644 --- a/app/onboarding/onboarding-flow.tsx +++ b/app/onboarding/onboarding-flow.tsx @@ -60,6 +60,10 @@ export function OnboardingFlow({ spaceName, steps, canSkip, profile: initialProf const [skillsText, setSkillsText] = useState(initialProfile.skills.join(', ')) const [formAnswers, setFormAnswers] = useState>>({}) const [formConsent, setFormConsent] = useState>({}) + // Form steps already submitted in THIS session. Prevents a second insert if + // the member navigates Back then Forward over a form/waiver step (the + // server-side alreadySubmitted prop is a snapshot from page load). + const [submittedNow, setSubmittedNow] = useState>({}) const step = steps[index] const isLast = index === steps.length - 1 @@ -69,7 +73,8 @@ export function OnboardingFlow({ spaceName, steps, canSkip, profile: initialProf const isFormStep = step.step_type === 'form' const formDef = step.formDef ?? null - const formActionable = isFormStep && formDef && !step.alreadySubmitted + const effectiveSubmitted = step.alreadySubmitted === true || submittedNow[step.id] === true + const formActionable = isFormStep && !!formDef && !effectiveSubmitted const isWaiver = formDef?.kind === 'waiver' const consentOk = !formActionable || !isWaiver || formConsent[step.id] === true @@ -131,6 +136,7 @@ export function OnboardingFlow({ spaceName, steps, canSkip, profile: initialProf toast.error(res.error) return } + setSubmittedNow(p => ({ ...p, [step.id]: true })) } await markOnboardingStepDone(step.id) setBusy(false) @@ -243,7 +249,7 @@ export function OnboardingFlow({ spaceName, steps, canSkip, profile: initialProf

This form is not available right now. You can continue.

- ) : step.alreadySubmitted ? ( + ) : effectiveSubmitted ? (

You have already completed this. You can continue.