Skip to content

fix(gift): redeem well-formed gift codes instead of rejecting every o… - #1099

Merged
thlpkee20-wq merged 1 commit into
Stellabill:mainfrom
Talentgift24-ux:fix/1013-gift-code-validation
Oct 24, 2026
Merged

thlpkee20-wq merged 1 commit into
Stellabill:mainfrom
Talentgift24-ux:fix/1013-gift-code-validation

Conversation

@Talentgift24-ux

Copy link
Copy Markdown
Contributor

#1013 fix(gift): every well-formed gift code is rejected as "not recognized" because of a length check that can never pass

Close#1013
RedeemGift validated codes against ^GIFT-[A-Z0-9]{6}-[A-Z0-9]{6}$ (always 18
characters) and then rejected anything shorter than 20 characters. Every code that
passed the format check therefore failed the length check, so the redemption flow was
unreachable — including codes handed out by GiftPurchaseModal. The resolved payload was
also discarded and replaced with a duplicated hardcoded gift object.

Changes

  • New src/utils/giftCode.ts — owns code normalisation, generation and validation:
    • normalizeGiftCode() uppercases, strips whitespace/separators, and accepts the code
      with or without dashes and with or without the GIFT prefix, so
      gift-abc123-xyz789, GIFT ABC123 XYZ789 and ABC123XYZ789 all resolve to
      GIFT-ABC123-XYZ789. Replaces the old formatCode(), which blindly prepended
      GIFT- and produced GIFT-GIFTABC123XYZ789 for pasted codes.
    • generateGiftCode() — crypto-random, always emits a canonical 12-character body. The
      previous Math.random().toString(36).substring(2, 8) generator could emit short
      segments and codes that did not match the format.
    • validateGiftCode() — returns a typed result (ok | invalid | expired | redeemed)
      with the resolved gift details, instead of rejecting with a thrown object.
  • RedeemGift.tsx — renders the gift details that validation actually resolved (the
    duplicated mockGiftDetails object is gone), canonicalises the input on blur, and guards
    the ?code= auto-validation with a ref so a StrictMode double mount starts exactly one
    validation.
  • GiftPurchaseModal.tsx — uses the shared generateGiftCode(), so a purchased code is
    guaranteed to be redeemable.
  • RedeemConfirmModal.tsx — imports the single shared GiftDetails type instead of a
    second copy.

Testing

  • New src/utils/giftCode.test.ts: normalisation variants, malformed input, generated-code
    format/uniqueness, and each validateGiftCode outcome (ok / expired / redeemed /
    not_found / malformed).

  • src/pages/RedeemGift.test.tsx: added a regression test that a code produced by
    GiftPurchaseModal opens RedeemConfirmModal, the /redeem-gift?code=GIFT-ABC123-XYZ789
    repro, pasted-variant canonicalisation, and a StrictMode single-validation check. The old
    formats code input automatically case asserted the buggy GIFT-ABC123XYZ789 output and
    now asserts canonicalisation on blur.

  • I have not been able to run vitest locally (dependency install kept failing on a
    flaky network), so the new tests are unverified here — please treat the CI run as the
    first real signal.

Out of scope

  • A real gift-validation endpoint (validateGiftCode remains a placeholder service with the
    same latency and fixture codes as before).
  • GiftRedeemSuccess rendering.

…ne (Stellabill#1013)

RedeemGift validated codes against the 18-character GIFT-XXXXXX-YYYYYY pattern and
then rejected anything shorter than 20 characters, so no code the purchase flow
hands out could ever be redeemed. It also threw away the resolved payload and
re-rendered a duplicated hardcoded gift.

Move normalization and lookup into src/utils/giftCode.ts, accept loosely pasted
codes (case, spaces, missing dashes or prefix) instead of prefixing them blindly,
reuse the same generator in GiftPurchaseModal, and render the details the
validation resolves. The ?code= auto-validation now runs once per code so a
StrictMode double mount cannot start two validations.
@thlpkee20-wq
thlpkee20-wq merged commit 456a02a into Stellabill:main Oct 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants