You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The full application form is rendered, validated, autosaved, and submittable from the UI. The backend returns 501s for now; the frontend uses local state + optimistic updates and is structured so swapping in the real backend is a one-line change.
Tasks
Question rendering
ApplicationForm: hydrates from GET /api/v1/registration (which returns a typed mock), renders sections from questions.ts.
What this accomplishes: The form shows the actual application questions, organized into sections, in the right order.
QuestionField: dispatches to the right input component based on QuestionType.
What this accomplishes: Each question renders with the correct input — text, textarea, dropdown, multi-select, file upload — without any conditional spaghetti in the parent form.
ShortTextField, LongTextField, SelectField, MultiSelectField, FileUploadField: real shadcn-styled inputs with labels, help text, and inline error display.
What this accomplishes: Every field type looks like part of the same form. No mismatched styles.
FileUploadField renders a placeholder dropzone for now (real upload integration is Ticket 4's work).
What this accomplishes: The form layout is complete even without working uploads. The component slot is real.
Validation
All fields validate against the Zod schema from src/lib/application/schema.ts via React Hook Form's resolver.
What this accomplishes: Required fields, character limits, email formats, etc. all show inline errors as the user types or on blur.
Submit button is disabled until the form passes validation.
What this accomplishes: Users can't submit half-filled forms. They see exactly what's missing.
Autosave
Form state changes trigger a debounced (e.g., 2 seconds) POST /api/v1/registration call.
What this accomplishes: Users don't lose progress if they navigate away. The endpoint returns 501 right now, but the call is real — it'll just start working once backend is done
SubmitBar shows "Saved X seconds ago" with a live-updating timestamp, "Saving…" while a save is in flight.
What this accomplishes: Visible confidence that work isn't being lost. Critical for long forms.
Submit flow
Submit button opens a confirmation dialog ("Are you sure? You can edit until registration closes.")
What this accomplishes: Stops accidental submits and reassures users they're not locking themselves out.
On confirm, PUT /api/v1/registration is called. Loading state on the button. Toast on success → redirect to /dashboard. Toast on failure.
What this accomplishes: Clear feedback at submit time.
Resume / read-only states
If applicationStatus === 'submitted' and registration is still open, form is editable.
If applicationStatus === 'submitted' and registration is closed, form renders read-only.
What this accomplishes: Reflects the rules the backend will enforce. Users see "your application is submitted" with their answers visible but uneditable when the window closes.
Registration-closed state
If registration hasn't opened: render a friendly "Applications open on [date]" page instead of the form.
If registration is closed: render a "Applications are closed" page.
What this accomplishes: The page handles all states an applicant might hit, not just "form is open."
Styling
Form is desktop-friendly
Progress indicator at the top: "Section 2 of 5" or similar.
What this accomplishes: Long forms feel manageable when users can see where they are.
Definition of done
/application shows the full form with all question types rendering correctly.
Validation, autosave indicator, and submit confirmation all work end-to-end against the mocked API.
Read-only and pre-open/post-close states are all reachable by tweaking the mock response.
Goal
The full application form is rendered, validated, autosaved, and submittable from the UI. The backend returns 501s for now; the frontend uses local state + optimistic updates and is structured so swapping in the real backend is a one-line change.
Tasks
Question rendering
ApplicationForm: hydrates fromGET /api/v1/registration(which returns a typed mock), renders sections fromquestions.ts.QuestionField: dispatches to the right input component based onQuestionType.ShortTextField,LongTextField,SelectField,MultiSelectField,FileUploadField: real shadcn-styled inputs with labels, help text, and inline error display.FileUploadFieldrenders a placeholder dropzone for now (real upload integration is Ticket 4's work).Validation
src/lib/application/schema.tsvia React Hook Form's resolver.Autosave
POST /api/v1/registrationcall.SubmitBarshows "Saved X seconds ago" with a live-updating timestamp, "Saving…" while a save is in flight.Submit flow
PUT /api/v1/registrationis called. Loading state on the button. Toast on success → redirect to/dashboard. Toast on failure.Resume / read-only states
applicationStatus === 'submitted'and registration is still open, form is editable.applicationStatus === 'submitted'and registration is closed, form renders read-only.Registration-closed state
Styling
Definition of done
/applicationshows the full form with all question types rendering correctly.