feat(card): specific reason on the rejected-card screen + crypto reassurance#2310
Conversation
…assure The "We couldn't issue you a card" screen showed only a generic catch-all body. Surface the vetted, region-aware reason from the capability read-model (e.g. "Peanut cards aren't available in your state yet.") above a reassurance body — a declined card doesn't touch the rest of the account, so point the user back to crypto deposit / withdraw / pay, which still work.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 27 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThe card page's ChangesRejected state reason message
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Code-analysis diffPainscore total: 5845.51 → 5846.01 (+0.5) 🆕 New findings (6)
✅ Resolved (5)
|
🧪 UI test report — ✅ all greenSuites
📊 Coverage (unit)
⏱ 10 slowest test cases
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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.
Inline comments:
In `@src/app/`(mobile-ui)/card/page.tsx:
- Around line 568-580: The rejected card screen is being replaced by a loading
spinner while capabilities are still pending, which hides the intended fallback
copy and support CTA. In the card page render flow around
ApplicationStatusScreen, remove the capabilitiesLoading guard for the rejected
state and always render the rejected screen immediately. Keep using
railsForProvider('rain')[0]?.reason?.userMessage for reasonMessage so it can
populate later, and let ApplicationStatusScreen handle the no-reason case until
the capability read-model arrives.
In `@src/components/Card/__tests__/ApplicationStatusScreen.test.tsx`:
- Around line 27-45: The current tests only verify that the rejected reason
exists, not that it appears above the reassurance body as rendered by
ApplicationStatusScreen. Update the ApplicationStatusScreen test cases to assert
the DOM order between the reasonMessage text and REASSURANCE, using the
ApplicationStatusScreen render output so the placement contract is checked
directly. Also strengthen the fallback case by asserting no extra reason
paragraph is present in a generic way, not just by matching one example phrase.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9a58816f-8917-4597-a534-82f3b947e229
📒 Files selected for processing (3)
src/app/(mobile-ui)/card/page.tsxsrc/components/Card/ApplicationStatusScreen.tsxsrc/components/Card/__tests__/ApplicationStatusScreen.test.tsx
…nt (CodeRabbit) Don't spinner-gate the rejected screen on capabilities — it's useful without the reason (reassurance + support CTA), so show it now and fill reasonMessage once capabilities resolve. Strengthen the test to assert the reason renders ABOVE the body (DOM order) and to count paragraphs generically instead of phrase-matching.
Why
The "We couldn't issue you a card" screen showed only a generic catch-all body ("…duplicate attempt, incomplete documents, information mismatch, or regional restrictions"). Users couldn't tell what actually happened, and the dead-end framing implied the whole account was blocked.
What
rejectedcase): wait for capabilities, then pass the vetted reason from the capability read-model (railsForProvider('rain')[0].reason.userMessage) into the screen — mirrors the existingrequires-infocase. Falls back to the generic body when capabilities haven't resolved.body→ reassurance: "You can still use Peanut freely to deposit, withdraw, and pay with crypto." A declined card doesn't gate the rest of the account. The specific reason (e.g. "Peanut cards aren't available in your state yet.") renders above it via the existingreasonMessageslot.Tests
New
ApplicationStatusScreen.test.tsx(3): reason-above-body, reassurance-only fallback, Contact-support still wired. Card + capabilities suites green (114).Cross-repo
Requires peanut-api-ts ops/card-rejection-reason (PR #1086) to populate
reason.userMessagefor Rain rejections. Without it the screen falls back to the generic body — safe to merge in either order, best UX once both land.🤖 Generated with Claude Code