chore: back-merge main → dev (pre Sprint 148 release)#2273
Conversation
Companion to peanut-api-ts#1037 (Rain dispute webhook handling). Plumb extraData.dispute through the history transformer into the TransactionDetails.cardPayment block, render a "Disputed — <label>" row under the existing decline / cancellation / pending notes, and append an "Evidence requested" row when Rain has prompted the user for docs. Pill override: while the dispute is pending or inReview, flip the status pill to pending — a settled spend that's actively contested isn't really COMPLETED from the user's POV. Terminal dispute states (accepted / resolvedByMerchant / rejected / canceled) restore the underlying status. Suppress the existing "Authorized, awaiting settlement or reversal" sub-row when an active dispute is the reason for the pending pill — the dispute row IS the status story there.
feat(card-details): render Rain dispute status in receipt drawer
Card-eligible users (skip badge or admin grant — both collapse into cardInfo.hasCardAccess on the BE) were funneled to the region picker first: the home activation funnel only surfaced the card step after KYC + funding, and the carousel KYC prompt always pointed at /profile/identity-verification. For EU/NA users that picker maps the region intent to bridge-requirements and auto-enrolls Bridge bank rails, whose DB checks fail on many EU addresses — surfacing as a "blocked by Bridge / proof of address" detour for people who only ever wanted a card. Surface the card step first whenever the user is eligible and cardless, routing them to /card (KYC runs on rain-requirements — no regionIntent, no Bridge rails), and stop showing the region-picker carousel CTA to eligible users.
Extends the card-priority behavior to the region picker. When a user has card access (skip badge / admin grant -> cardInfo.hasCardAccess) but no active card, handleStartKyc now sends them to /card — whose KYC runs on the rain-requirements Sumsub level (no regionIntent, no Bridge/Manteca rail enrollment) — instead of starting region KYC, regardless of which region they selected. Card-holders fall through and can still unlock bank regions.
Address CodeRabbit (Major): while useRainCardOverview is still loading, treating `overview` as "no active card" could bounce a card-holder to /card before it resolves. Make hasActiveCard tri-state (undefined while loading) and only redirect on an explicit `false`.
fix(card): prioritize card CTA for eligible users over region-picker KYC
…nly) PIX deposits via Manteca (Brazil) are currently unstable/intermittent. We want users to still see and use the option, but to know it may be delayed or fail — so this surfaces a warning without removing the path. - new config lever underMaintenanceConfig.pixBrazilOnrampMaintenance (warn-only, Brazil-scoped — does not touch the Argentina/ARS Manteca onramp or QR pay, which the existing coarse disabledPaymentProviders:['MANTECA'] lever would) - "Maintenance" tag on the Pix option in /add-money/brazil (stays clickable) - warning banner inside the deposit flow (/add-money/brazil/manteca) Flip the flag to false when PIX deposits are stable again. Frontend-only: the API still accepts PIX deposits by design (warn-only).
…ce-warning feat(add-money): flag BRL-via-PIX onramp as under maintenance (warn-only)
A new recipient who opens a send link, registers/KYCs, and is redirected back to /claim hit a 404 'Send link not found' and could not claim (TASK-20193). The claim pubKey is derived from the link's #p= password fragment; the guest -> /setup -> KYC -> /claim flow fully remounts the page and the fragment comes back mangled (the c/v/i query survives), so the remounted page derives the wrong pubKey and 404s. Proven in prod: the failing GET used a pubKey absent from the DB while the real link at the same deposit slot (c=42161,v=v4.4,i=181) exists and is completed. Fix: resolveClaimLink keys the pristine link by its deposit slot (which the redirect preserves) in localStorage on first open; first write wins, so the correct password stays authoritative even if a later remount arrives with a broken fragment. Slot-local + client-only, so nothing new is exposed.
claim-states mounts <Claim/>, which now calls resolveClaimLink; the module mock must expose it or the suite throws 'resolveClaimLink is not a function'.
…tring CodeQL flagged externally-controlled-format-string (high): resolveClaimLink builds the localStorage key from user-controlled URL params, which then reached saveToLocalStorage's console.log as the format string. Pass key as a trailing arg so a %s/%d in a link can't be interpreted as a format specifier.
When adding a bank account for a send-link payout fails, the backend now returns a curated, user-facing message (e.g. 'we couldn't verify your bank's billing address — check city/state/ZIP'). Routing it through ErrorHandler collapsed it into the generic 'contact support' fallback, hiding the actionable detail. Surface response.error verbatim for this path; keep FE Sentry capture. (TASK-20194, companion to peanut-api-ts external-account fix)
fix(claim): surface backend bank-account error verbatim [hotfix]
…into-dev-20260623
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThis PR bundles four independent changes: a warn-only Brazil PIX onramp maintenance banner (flag, countries-list badge, in-flow ChangesPIX Brazil Onramp Maintenance Banner
Card Activation Funnel Priority
Claim Link Fragment Preservation
Rain Card Dispute Lifecycle Display
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
🚥 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
Comment |
Code-analysis diffPainscore total: 5807.46 → 5811.68 (+4.22) 🆕 New findings (100)
…and 80 more. ✅ Resolved (98)
…and 78 more. 📈 Painscore deltas (top movers)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/hooks/useActivationStatus.ts (1)
119-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider tri-state handling for
hasCardto prevent flash during loading.Currently
hasCardis computed as!!findActiveCard(overview), which evaluates tofalsewhileoverviewis loading. IfcardInfoloads beforeoverview, a user who has an active card would briefly match the condition and see the card CTA. Since the CTA is dismissable (line 24), they might accidentally dismiss it during the loading window, persisting the dismissal even afteroverviewloads and reveals they have a card.UnlockedRegions.view.tsx (lines 75-78) uses explicit tri-state handling for the same field to prevent similar issues:
const hasActiveCard = useMemo<boolean | undefined>(() => { if (!overview) return undefined return !!findActiveCard(overview) }, [overview])Then the guard checks
hasCard === falseinstead of!hasCard.♻️ Proposed refactor
- const hasCardAccess = cardInfo?.hasCardAccess ?? false - const hasCard = !!findActiveCard(overview) - if (hasCardAccess && !hasCard && !cardDismissed) { + const hasCardAccess = cardInfo?.hasCardAccess ?? false + const hasCard = overview === undefined ? undefined : !!findActiveCard(overview) + if (hasCardAccess && hasCard === false && !cardDismissed) { activationStep = 'card' }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useActivationStatus.ts` around lines 119 - 122, The hasCard variable needs to use tri-state handling to prevent false positives during loading. Wrap the hasCard computation in a useMemo hook that returns undefined when overview is not yet loaded, otherwise returns the boolean result of findActiveCard(overview). Update the condition check from !hasCard to hasCard === false to properly handle the three states (undefined for loading, false when no card, true when card exists). This prevents the card CTA from briefly appearing and being accidentally dismissed when cardInfo loads before overview.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/hooks/useActivationStatus.ts`:
- Around line 119-122: The hasCard variable needs to use tri-state handling to
prevent false positives during loading. Wrap the hasCard computation in a
useMemo hook that returns undefined when overview is not yet loaded, otherwise
returns the boolean result of findActiveCard(overview). Update the condition
check from !hasCard to hasCard === false to properly handle the three states
(undefined for loading, false when no card, true when card exists). This
prevents the card CTA from briefly appearing and being accidentally dismissed
when cardInfo loads before overview.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b99d14dd-87b2-41f5-9ca7-6555d3b35a50
📒 Files selected for processing (19)
src/app/(mobile-ui)/add-money/__tests__/add-money-states.test.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/components/AddWithdraw/AddWithdrawCountriesList.tsxsrc/components/AddWithdraw/__tests__/AddWithdrawCountriesList.test.tsxsrc/components/Claim/Claim.tsxsrc/components/Claim/Link/views/BankFlowManager.view.tsxsrc/components/Claim/__tests__/claim-states.test.tsxsrc/components/Profile/views/UnlockedRegions.view.tsxsrc/components/TransactionDetails/provider-rows/CardPaymentRows.tsxsrc/components/TransactionDetails/provider-rows/__tests__/dispute-label.test.tssrc/components/TransactionDetails/transactionTransformer.tssrc/config/underMaintenance.config.tssrc/hooks/useActivationStatus.tssrc/hooks/useHomeCarouselCTAs.tsxsrc/services/__tests__/resolveClaimLink.test.tssrc/services/sendLinks.tssrc/utils/general.utils.tssrc/utils/history.utils.ts
Back-merge
main→devBrings the 14 hotfix commits that landed directly on
mainsince the last release back intodev, so the upcoming Prod Release Sprint 148 PR (dev → main, #2245) is a clean superset of main with no surprise reverts/conflicts.Merge was conflict-free.
Hotfixes pulled back from main
fix(claim)show the backend's bank-account error verbatimfix(security)pass localStorage key as a console arg, not a format stringfix(claim)preserve send-link password across the auth/KYC redirect (+ test stub)feat(add-money)flag BRL-via-PIX onramp as under maintenance (warn-only)fix(card)hasActiveCard tri-state + region-picker redirect fixes (3 commits)feat(card-details)render Rain dispute status in the receipt drawer (+ CR follow-up)Why a PR (not a direct push)
Matches the established back-merge pattern (cf. #2256) and lets CI/Vercel-preview validate before it lands on the shared
devbranch that staging tracks.Automated as part of the Sprint 148 release prep.