Toronto Voter Survey - #52
Conversation
The questions lived here in surveyData.ts, which was a deliberate choice while this was the only thing rendering them: rewording a question needed no deploy on the API side. Candidates now answer surveys too, and a candidate questionnaire is authored in York Factory's CMS — a question set that only exists in the front end can't be rendered as an admin form. So the database became the source of truth and this follows it. The renderer is unchanged in spirit: it still derives step count, progress, validation and the submitted payload from whatever steps it's given, only now they arrive over the wire. Adding a question is a CMS edit with no deploy here at all, which is more than the old arrangement managed. Three things follow from the move: - The submitted slug and version come from the survey that was actually rendered rather than constants, so answers can't be filed under a question set the respondent never saw. - yesno options come from the API like any other choice list, so the values published results group by have one definition rather than a copy on each side. - Ward choices are resolved from the election's councillor races when the survey is served, so the list can't drift from the ward pages the way a frozen copy in this repo did. The page 404s when the definition can't be fetched and the ISR cache is cold. A half-rendered form is worse than an honest miss, and keeping a hard-coded fallback here is the drift this change exists to end. Depends on york_factory#100: production has no /surveys endpoint until that ships. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Greptile SummaryThe PR adds a CMS-driven, multi-step Toronto voter survey and a proxy that records responses through York Factory. It also extracts shared postal-code normalization and introduces a main-site select primitive.
Confidence Score: 4/5The PR should not merge until the York Factory survey-definition and response endpoints it requires are available, because the current backend leaves the new page and submission flow unusable. Both mandatory network boundaries in the new survey flow target routes absent from the current York Factory repository, causing the page to resolve to a 404 and preventing responses from being recorded. Files Needing Attention: src/lib/elections/survey.ts and src/app/api/elections/survey/route.ts
|
| Filename | Overview |
|---|---|
| src/lib/elections/survey.ts | Defines the remote survey contract and fetches it from a York Factory endpoint that is absent from the current backend. |
| src/app/api/elections/survey/route.ts | Validates and forwards survey responses, but targets an unregistered York Factory endpoint. |
| src/app/toronto/elections/2026/survey/page.tsx | Loads the remote survey and deliberately converts upstream fetch failures into a page-level 404. |
| src/app/toronto/elections/2026/survey/SurveyClient.tsx | Implements the dynamic multi-step renderer, validation, navigation, and retry-preserving submission flow. |
| src/app/toronto/elections/2026/survey/submitSurvey.ts | Builds the survey payload from rendered answers and records successful submissions in PostHog. |
| src/components/ui/select.tsx | Adds a controlled Base UI select styled for the main site. |
| src/lib/elections/postal-code.ts | Extracts the existing Canadian postal-code validation and normalization behavior for reuse. |
Sequence Diagram
sequenceDiagram
participant V as Voter
participant T as Tradingpost Survey Page
participant P as Tradingpost API Proxy
participant Y as York Factory
V->>T: Open Toronto survey
T->>Y: "GET /elections/{election}/surveys/{slug}"
Y-->>T: 404 (route not registered)
T-->>V: Not Found
V->>P: Submit completed answers
P->>Y: "POST /elections/{election}/survey_responses"
Y-->>P: 404 (route not registered)
P-->>V: Survey submission failed
Prompt To Fix All With AI
### Issue 1
src/lib/elections/survey.ts:108-111
**Backend survey routes are missing**
The survey page always requests `GET /elections/{election}/surveys/{survey}`, but the current York Factory election routes register only pledges, so the request returns 404 and `loadSurvey` turns the new page into a not-found response. The submission proxy likewise targets an unregistered `POST /elections/{election}/survey_responses` route, preventing responses from being recorded.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "survey context" | Re-trigger Greptile
| ): Promise<Survey> { | ||
| const { data } = await apiFetch<{ data: Survey }>( | ||
| `/elections/${electionSlug}/surveys/${surveySlug}`, | ||
| { revalidate: 300, tags: [`survey:${electionSlug}:${surveySlug}`] }, |
There was a problem hiding this comment.
Backend survey routes are missing
The survey page always requests GET /elections/{election}/surveys/{survey}, but the current York Factory election routes register only pledges, so the request returns 404 and loadSurvey turns the new page into a not-found response. The submission proxy likewise targets an unregistered POST /elections/{election}/survey_responses route, preventing responses from being recorded.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/lib/elections/survey.ts
Line: 108-111
Comment:
**Backend survey routes are missing**
The survey page always requests `GET /elections/{election}/surveys/{survey}`, but the current York Factory election routes register only pledges, so the request returns 404 and `loadSurvey` turns the new page into a not-found response. The submission proxy likewise targets an unregistered `POST /elections/{election}/survey_responses` route, preventing responses from being recorded.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
No description provided.