fix(promocode): preserve ticket type chip labels after validation error#923
Conversation
PromocodeForm.handleSubmit mutated state.entity.allowed_ticket_types
from [{id,name}] to [id] before calling onSubmit. The mutated entity
flowed into redux via UPDATE_PROMOCODE (start action), and on a 412
response no re-hydration happened — the form re-rendered with raw IDs,
and TicketTypesInput's getOptionLabel template literal `${e.name}`
coerced (number).name into the literal string "undefined" for each chip.
Move the ID extraction into normalizeEntity in the action layer so only
the request body is dehydrated; redux and form state stay hydrated.
Adds a regression test asserting onSubmit receives an entity whose
allowed_ticket_types retains {id,name} objects.
Refs ClickUp 86b9v01bt
Jam: https://jam.dev/c/b1566c62-c802-4f43-b093-9c5c2f5a5fde
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
💤 Files with no reviewable changes (1)
📝 WalkthroughWalkthroughThis PR refactors where ChangesPromo Code Ticket Types Normalization Refactor
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsTimed out fetching pipeline failures after 30000ms Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Fixes a Promo Code form regression where selected “Ticket Types” chips could display "undefined" after a server-side validation error by preventing in-place dehydration of allowed_ticket_types in component state and moving dehydration to the action normalization layer.
Changes:
- Removed
allowed_ticket_typesin-place mutation fromPromocodeForm.handleSubmit. - Added
allowed_ticket_typesdehydration tonormalizeEntityinpromocode-actions.jsso only the API request body is normalized. - Added an integration regression test to ensure
onSubmitreceives a hydratedallowed_ticket_typesarray of{id, name}objects.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/components/forms/promocode-form/index.js | Stops mutating state.entity.allowed_ticket_types during submit, preserving hydrated option objects across validation failures. |
| src/actions/promocode-actions.js | Normalizes allowed_ticket_types in the action layer to send IDs to the API without corrupting redux/form state. |
| src/components/forms/promocode-form/tests/promocode-form.integration.test.js | Adds a regression test asserting handleSubmit does not dehydrate allowed_ticket_types before calling onSubmit. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| if (Array.isArray(entity.allowed_ticket_types)) { | ||
| normalizedEntity.allowed_ticket_types = entity.allowed_ticket_types.map( | ||
| (tt) => (typeof tt === "object" && tt !== null ? tt.id : tt) |
ref: https://app.clickup.com/t/86b9v01bt
ref: https://jam.dev/c/b1566c62-c802-4f43-b093-9c5c2f5a5fde
Summary
After a server validation error (e.g. POST returning 412 for a missing required
code), the Promo Code form's "Ticket Types" chips would revert to displaying the literal stringundefinedfor each previously-selected option.Two-layer corruption:
PromocodeForm.handleSubmitmutatedstate.entity.allowed_ticket_typesfrom[{id, name, …}]to[id, …]in place, before callingonSubmit.savePromocodedispatchesUPDATE_PROMOCODE(start action) with that same entity reference; the reducer (promocode-reducer.js:131-133) spreads the now-dehydrated payload intostate.entity. On a 412 noPROMOCODE_ADDEDre-hydration runs, so the form re-renders with raw IDs. uicore'sTicketTypesInputdefaultsgetOptionLabelto`${e.name}`— for a raw number(197).nameisundefined, the template literal coerces it to the string"undefined", and that's what every chip displays.Fix
handleSubmit— the form handsonSubmitthe unmodified entity.normalizeEntityin the action layer, alongside the existingtagsmapping. Only the request body is dehydrated; redux state and the form'sstate.entitystay hydrated.This also incidentally cures a latent symptom on the PUT path (existing-code edits):
PROMOCODE_UPDATEDdoesn't re-hydrate from response, so post-fix successful PUTs also keep chips intact.Test plan
promocode-form.integration.test.jsassertingonSubmitreceives an entity whoseallowed_ticket_typesretains{id, name}objects. Verified to fail pre-fix (received[197]), pass post-fix.DOMAIN_AUTHORIZED_PROMO_CODEwith the email domains pre-populated and "Early Access Members" added, clicked Save without typingcode, dismissed the 412 toast — chip still reads "Early Access Members" (was "undefined" pre-fix).Refs
🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests