Skip to content

#562 File Answers Can Be Edited When Withdrawn - #596

Open
b-at-neu wants to merge 2 commits into
devfrom
562-file-answers-editable-when-withdrawn
Open

#562 File Answers Can Be Edited When Withdrawn#596
b-at-neu wants to merge 2 commits into
devfrom
562-file-answers-editable-when-withdrawn

Conversation

@b-at-neu

Copy link
Copy Markdown
Collaborator

Closes #562

Summary

  • File answers hardcoded 'draft' in two places in prisma/actions/question-files.ts, while text answers already gated on APPLICANT_EDITABLE_APPLICATION_STATUSES (draft|withdrawn) — a withdrawn applicant could edit their text answers but not replace or remove a file answer. Both gates now use the same predicate.
  • APPLICATION_NOT_EDITABLE_MESSAGE moves from a module-private constant in prisma/actions/applications.ts to a shared export in lib/constants.ts, so both answer types return the identical sentence for the same situation instead of file answers returning the misleading "This application has already been submitted." (which used to fire even for accepted/rejected).
  • No UI change was needed: the apply page, the withdrawn-row primary action, and AnswerField already support this once the server actions stop refusing the write.

Changes

  • lib/constants.ts — added isApplicantEditableApplicationStatus (mirrors isNonReviewableApplicationStatus's shape) and the exported APPLICATION_NOT_EDITABLE_MESSAGE.
  • prisma/actions/question-files.tsauthorizeTarget's pre-check and readAndWriteAnswerValue's in-transaction guard both now accept draft|withdrawn; renamed ApplicationSubmittedErrorApplicationNotEditableError; removed the local SUBMITTED_ERROR copy.
  • prisma/actions/applications.ts — dropped the module-private message constant in favor of the lib/constants.ts export; replaced the two unsafe-cast .includes() checks with the new predicate.
  • app/(main)/(auth)/positions/[id]/apply/page.tsx — same predicate swap for isEditable.
  • tests/stubs/vercel-blob.ts (new) — alias target for @vercel/blob in the db test project; exposes onPut/deletedUrls/resetBlobStub so the race test can flip application status mid-upload.
  • vitest.config.ts — registers the @vercel/blob alias for the db project.
  • tests/db/question-file-answers.test.ts (new) — status matrix for uploadQuestionFileAnswer/removeQuestionFileAnswer (both isGlobal: true/false), plus the post-pre-check race case.
  • docs/PERMISSIONS.md — rewrote the question-files.ts server-action-authorization row; removed the now-closed File answers can't be edited when withdrawn, unlike text answers #562 "Known-open deviations" entry.
  • docs/WORKFLOWS.md — AP-8's stale-tab bullet and AP-14's happy path updated to reflect that file answers are editable on a withdrawn application, with the shared error copy.

Testing plan

  • Seed a position with a required file_upload position question, apply as an applicant, upload a PDF, and submit.
  • Withdraw the application from /my-applications, then click Edit & resubmit.
  • On step 2, click Replace, pick a different PDF → toast "File uploaded", filename updates, Download serves the new file.
  • Click Remove → confirm the dialog → toast "File removed", row returns to "No file uploaded yet."
  • Upload again and Resubmit → toast "Application resubmitted"; /my-applications/[id] shows the new file.
  • Step 1: click Customize, replace a global file answer, and confirm /profile still shows the original file (the profile's blob must survive the reference count).
  • Stale-tab check: with the apply page open on the withdrawn application, resubmit it in a second tab, then Replace in the first → inline error + toast "This application has already been submitted. Withdraw it to make changes.", and the file is unchanged.
  • Confirm a decided application still refuses: set one to accepted, visit /positions/[id]/apply → the "You've already applied" card, no editor.
  • tests/db/question-file-answers.test.ts — upload/remove succeed exactly on draft/withdrawn and return the shared message otherwise, over every ApplicationStatus, for both global and position-scoped questions; the post-pre-check race returns the message, records a del of the new blob, and leaves the stored value untouched.

Automated checks

  • npm run prettier:check — pass
  • npm run eslint:check — pass
  • npm run tsc:check — pass
  • npm run test:unit — pass (227/227)
  • npm run test (db project) — could not run locally: port 5432 was already bound by an unrelated process in this sandbox, so Postgres couldn't be started via npm run db:start. The new tests/db/question-file-answers.test.ts follows the exact status-matrix pattern already proven in tests/db/application-transitions.test.ts (same fixtures, same actAs/isError helpers) and will run in CI.

Notes

  • The literal 'This application has already been submitted. Withdraw it to make changes.' is asserted verbatim (not imported) in both tests/db/application-transitions.test.ts and the new tests/db/question-file-answers.test.ts, per plan — importing the constant would let a copy change pass silently.
  • "Withdraw it to make changes" is still imprecise for accepted/rejected (where withdraw is itself blocked); this ticket intentionally chose copy consistency with the text-answer path over per-status accuracy.

Both hardcoded 'draft' gates in question-files.ts (the pre-check and
the in-transaction findFirst) now use APPLICANT_EDITABLE_APPLICATION_STATUSES,
matching the text-answer path. APPLICATION_NOT_EDITABLE_MESSAGE moves
to lib/constants.ts so both answer types share one sentence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu b-at-neu added the claude Will be worked on by Claude label Aug 24, 2026
@b-at-neu b-at-neu self-assigned this Aug 24, 2026
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
aplio Ready Ready Preview Aug 24, 2026 10:06pm

@b-at-neu b-at-neu added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed ready for review PR ready for review agent labels Aug 24, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 1 · needs revision

1 open — 1 🟡 Low (see inline)

Comment thread tests/stubs/vercel-blob.ts Outdated
@b-at-neu b-at-neu added needs revision Review found issues that need fixing revising Revise agent working (in-flight) and removed reviewing Review agent working (in-flight) needs revision Review found issues that need fixing labels Aug 24, 2026
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@b-at-neu

Copy link
Copy Markdown
Collaborator Author

Revision — Cycle 1

fixed R1-L1 · f1fd25b

@b-at-neu b-at-neu added ready for review PR ready for review agent reviewing Review agent working (in-flight) and removed revising Revise agent working (in-flight) ready for review PR ready for review agent labels Aug 24, 2026

@b-at-neu b-at-neu left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — Cycle 2 · approved

0 open — R1-L1 resolved, no regressions

@b-at-neu b-at-neu added approved Review passed, ready to merge refresh branch Rebase onto base and force-push to trigger a fresh preview deployment refreshing Revise agent refreshing the branch (in-flight) and removed reviewing Review agent working (in-flight) refresh branch Rebase onto base and force-push to trigger a fresh preview deployment labels Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Review passed, ready to merge claude Will be worked on by Claude refreshing Revise agent refreshing the branch (in-flight)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File answers can't be edited when withdrawn, unlike text answers

1 participant