#731 Display And Store Phone Numbers In One Format - #752
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
b-at-neu
left a comment
There was a problem hiding this comment.
Code Review — Cycle 1 · needs revision
1 open — 1 🟡 Low
R1-L1 🟡 Low — AnswerMismatchNotice renders orphaned short_answer values raw (no formatShortAnswerValue), so a legacy multi-value phone_number row shows unmasked extra digits in the mismatch notice — the one render surface the ticket's "verified by grep" acceptance criterion missed. Fix: run values through formatShortAnswerValue/pass format down from AnswerDisplay.
aplio/components/features/answer-mismatch-notice.tsx
Lines 39 to 45 in 6b29bf0
6b29bf0 to
2db1cd3
Compare
Revision — Cycle 1fixed R1-L1 · 2db1cd3 |
b-at-neu
left a comment
There was a problem hiding this comment.
Code Review — Cycle 2 · approved
1 open — 1 ⚪ Nit (see inline)
2db1cd3 to
4964bc2
Compare
4964bc2 to
8ff9988
Compare
Revision — rebaserebase: docs/WORKFLOWS.md (merged independent insertions), tests/unit/constants.test.ts (merged independent import additions) · 8ff9988 |
d77c17d to
b015b01
Compare
Revision — Cycle 3fixed R2-N1 · b015b01 R3-L1 investigated: no code-level cause found. The diff has no schema/migration/route changes, no env-dependent code, and nothing edge-runtime-incompatible. The failed deployment ( |
b-at-neu
left a comment
There was a problem hiding this comment.
Code Review — Cycle 4 · approved
0 open — clean
Store new phone_number answers as digits with an optional leading +, and mask 10/11-digit US-shaped values on every short-answer renderer. Unparseable and international values render exactly as stored, and existing rows are never backfilled. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run orphaned short_answer values through formatShortAnswerValue in AnswerMismatchNotice so a legacy multi-value phone_number row masks consistently in the mismatch notice. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
b015b01 to
e3c1561
Compare
Revision — Cycle 4rebased onto origin/dev · e3c1561 · rebase: docs/WORKFLOWS.md (union merge — both sides added distinct non-overlapping sentences to the same AP-11/PM-9 paragraphs; kept both) |
b-at-neu
left a comment
There was a problem hiding this comment.
Code Review — Cycle 5 · approved
0 open — clean
Closes #731
Summary
phone_numberanswers are stored normalized. No backfill — existing rows render unchanged through the tolerant path.libphonenumber-js— confirms the ticket's recommendation, since the validator is already deliberately loose and the masking rule is US-only by design.Changes
lib/constants.ts— addednormalizePhoneNumber,formatPhoneNumber, and the two format-dispatching helpersnormalizeShortAnswerValue/formatShortAnswerValue, placed besidematchesShortAnswerFormat.lib/types.ts— addedformat: ShortAnswerFormat | nulltoApplicationReviewAnswer(AnswerQuestionalready had it).prisma/data/applications.ts— selectsformatthrough the live question relations (including for orphaned/soft-deleted questions) and maps it into all four branches ofnormalizeApplicationAnswers.prisma/actions/profile.ts(updateGlobalAnswer) andprisma/actions/applications.ts(createOrUpdateApplicationAnswer) — the write path now runs each short-answer value throughnormalizeShortAnswerValueinstead of a bare.trim(). Runs strictly after existing validation; the profile-copy branch forfile_uploadanswers is untouched.components/features/answer-display.tsxandcomponents/features/application-answers-list.tsx— the single-value and chip-list short-answer branches render throughformatShortAnswerValue, covering both the profile view and the reviewer/applicant answer list.tests/unit/constants.test.ts— unit coverage fornormalizePhoneNumber/formatPhoneNumber(10-digit, 11-digit leading 1, already-normalized,+international,00international, 7-digit local, a validator-passing value that fits no mask — each round-tripped normalize → format) and for the dispatchers' identity behavior on other formats.tests/db/phone-number-normalization.test.ts(new) — confirmsupdateGlobalAnswerandcreateOrUpdateApplicationAnswerboth store a digits-only value for a punctuated input.docs/WORKFLOWS.md— one clause each in AP-2, AP-6, AP-11, PM-9 describing the storage/display rule.Testing plan
(617) 555-0100on/profile, reload — the read-only card shows(617) 555-0100.6175550100(digits only) via the DB or the edit field.+44 20 7123 4567— stored+442071234567, displayed unchanged as+442071234567.555-123-4567) directly in the DB — the profile card and the reviewer view both show(555) 123-4567, and the row itself is untouched./manage/applications/<id>— the answer renders masked in the answers list.abcin a phone field — stillEnter a valid phone numberinline, nothing saved (unchanged behavior).email,url, andzip_codequestion and a long answer — rendering byte-identical to before this change.short_answerrow (more than one value, formatphone_number) — each chip formats independently.Automated checks
npm run prettier:check— passnpm run eslint:check— passnpm run tsc:check— passnpm run test:unit— pass (77/77 intests/unit/constants.test.ts; full unit suite 423/423, one pre-existing unrelated failure intests/unit/email-delivery-events.test.tsdue to no localDATABASE_URL)tests/db/phone-number-normalization.test.tsadded but not run locally — no Postgres available in this worktree (DATABASE_URLunset, and the localdb:startport is already occupied by an unrelated container). Will run in CI'srun-testscheck.Notes
AnswerField) deliberately keeps showing the raw stored value while the read-only card shows the mask — formatting a controlled autosave input would desync the stepper's dirty/diff tracking for a cosmetic gain.type="tel"and the validator are unchanged.findDivergingGlobalAnswersis string-exact, so re-saving an application phone answer can flag a purely cosmetic divergence against an untouched legacy profile value. Cosmetic only — "Revert to profile answers" still writes the correct profile value; not worth normalizing the copy path, which would be a backfill by the back door.00→+promotion is the one rule the ticket left implicit — it follows from the validator treating both as the same prefix, and is covered by a round-trip unit test.