diff --git a/components/EngagementForm.tsx b/components/EngagementForm.tsx index b19e111..5f44493 100644 --- a/components/EngagementForm.tsx +++ b/components/EngagementForm.tsx @@ -19,6 +19,7 @@ function sectionForField( import { evaluate } from "@/lib/conditional"; import { STAGE_OPTION_GROUP_ID } from "@/config/form"; import { StageSection } from "./StageSection"; +import { FieldRenderer } from "./fields/FieldRenderer"; import { loadDraft, saveDraft, clearDraft } from "@/lib/draft"; interface EngagementFormProps { @@ -241,6 +242,26 @@ export function EngagementForm({ config, cid, cs }: EngagementFormProps) { const currentRank = currentStageValue ? STAGE_RANK[currentStageValue] ?? 0 : 0; + // Section pathway state — past / current / future is determined entirely + // by stage rank vs the org's current rank. Sections never hide; future + // stages render in a locked treatment so users can preview what's ahead. + // + // Section-level visibleWhen is still consulted on submit to strip + // locked-stage values from the payload (see onSubmit below), so a future + // stage's data never gets accidentally written. + // The submitter-info section (rank: -1) lives outside the stage pathway — + // it renders directly above the section list (see JSX below), not inside + // the rail/marker accordion model used for Stage 0..5. Filter it out here + // so its rank doesn't pollute the past/current/future calculation. + const submitterSection = useMemo( + () => config.sections.find((s) => s.id === "submitter_info"), + [config.sections], + ); + const stageSections = useMemo( + () => config.sections.filter((s) => s.id !== "submitter_info"), + [config.sections], + ); + // Section pathway state — past / current / future is determined entirely // by stage rank vs the org's current rank. Sections never hide; future // stages render in a locked treatment so users can preview what's ahead. @@ -250,12 +271,12 @@ export function EngagementForm({ config, cid, cs }: EngagementFormProps) { // stage's data never gets accidentally written. const sectionsToRender = useMemo( () => - config.sections.map((s) => { + stageSections.map((s) => { const pathwayState: PathwayState = s.rank < currentRank ? "past" : s.rank === currentRank ? "current" : "future"; return { section: s, pathwayState, locked: pathwayState === "future" }; }), - [config.sections, currentRank], + [stageSections, currentRank], ); // Track which sections the user has manually opened/closed so we can @@ -398,6 +419,38 @@ export function EngagementForm({ config, cid, cs }: EngagementFormProps) { }} /> )} + {submitterSection && ( +
+

+ {submitterSection.label} +

+ {submitterSection.intro && ( +

{submitterSection.intro}

+ )} +
+ {submitterSection.fields.map((f) => ( + + ))} +
+
+ )} +
    {sectionsToRender.map((entry, i) => { const { section, pathwayState, locked } = entry; diff --git a/config/form.ts b/config/form.ts index d81351b..2baef4b 100644 --- a/config/form.ts +++ b/config/form.ts @@ -54,6 +54,36 @@ const G5 = "Stage_5"; // route through Contact.update on submit and Contact.get at form load. const G_ORG = "Food_Co_op_Organizing"; +// Submitter information — captured on every check-in. Rendered above the +// stage pathway (see EngagementForm) so it's not threaded into the past / +// current / future stage rail. Both fields are required on every submission. +// rank: -1 keeps the section out of the rank-based pathway computation; +// EngagementForm filters this section out of `sectionsToRender` and renders +// it directly via FieldRenderer above the stage list. +const submitterInfo: StageSectionConfig = { + rank: -1, + id: "submitter_info", + label: "Survey submitter", + intro: + "Who's filling this out? We log this with each submission so we can follow up if needed.", + fields: [ + { + name: "Survey_completed_by", + label: "Survey completed by", + type: "text", + required: true, + civiField: `${G0}.Survey_completed_by`, + }, + { + name: "Survey_completed_by_email", + label: "Survey completed by — email", + type: "email", + required: true, + civiField: `${G0}.Survey_completed_by_email`, + }, + ], +}; + // Stage 0 — Survey (always visible) const stage0: StageSectionConfig = { rank: 0, @@ -753,7 +783,7 @@ export const formConfig: FormConfig = { subtitle: "Thank you for updating your co-op information. The questions you'll see depend on where you are in the Framework.", stageField: "current_stage", - sections: [stage0, stage1, stage2, stage3, stage4, stage5], + sections: [submitterInfo, stage0, stage1, stage2, stage3, stage4, stage5], }; /** Convenience: flatten all field configs across all sections for lookup by name. */