Skip to content

fix(qa): post-cutover FE crashes + receipt label regressions#1910

Merged
Hugo0 merged 4 commits intodevfrom
qa/post-cutover-fe-fixes
Apr 29, 2026
Merged

fix(qa): post-cutover FE crashes + receipt label regressions#1910
Hugo0 merged 4 commits intodevfrom
qa/post-cutover-fe-fixes

Conversation

@Hugo0
Copy link
Copy Markdown
Contributor

@Hugo0 Hugo0 commented Apr 29, 2026

Summary

Companion to backend PR peanutprotocol/peanut-api-ts#675. Five FE files defensively handle Account-shape regressions from the staging cutover and fix two receipt-rendering bugs surfaced in Hugo's manual QA pass.

Bugs fixed

  1. Saved-accounts page crashCannot read properties of null (reading 'countryName') at AddWithdrawRouterView.onAccountClick. After the phase-2 consolidate, every legacy account had details: null because provider_account_links was empty. The handler crashed on account.details.countryName before the user could even act on the account. Backend PR [TASK-7066] refactor: new endpoints request #675 also makes the API always emit a non-null details shape; this FE patch is the second line of defense.

  2. "Sent to Sent via link" drawer header on completed link sends. The link-transaction short-circuit in TransactionDetailsHeaderCard.getTitle only fired when (status === 'pending' || 'cancelled' || !userName), so completed link sends fell through to the generic Sent to ${displayName} composition where displayName === 'Sent via link'. Now the short-circuit fires for any link transaction with explicit per-status / per-direction handling.

  3. Missing icon on saved bank accounts whose countryCodeForFlag is empty (legacy accounts without provider-link metadata). The 8x8 flag image was conditionally rendered, leaving a bare yellow bank badge floating over empty space. Added a grey placeholder so the row reads as intentional.

  4. account.details?.countryCode / accountOwnerName optional-chained in BankFlowManager.view.tsx (2 sites) and bridge.utils.ts.getCountryFromAccount — defensive coverage of the same null-details regression on lower-traffic paths.

Files

File Change
AddWithdraw/AddWithdrawRouterView.tsx ?.countryName ?? '' optional-chain in onAccountClick
Common/SavedAccountsView.tsx Grey-placeholder fallback when countryCodeForFlag is empty
TransactionDetails/TransactionDetailsHeaderCard.tsx Drop the (pending|cancelled|!userName) gate; explicit per-direction handling
Claim/Link/views/BankFlowManager.view.tsx ?.countryCode ?? '' and ?.accountOwnerName
utils/bridge.utils.ts account.details?.countryCode/countryName

Test plan

  • pnpm typecheck clean
  • npm test — 928 tests / 36 suites pass
  • Apply backend PR [TASK-7066] refactor: new endpoints request #675 migrations to staging; verify saved-accounts page renders without crash
  • Click into a saved IBAN: no client-side exception
  • Open a completed SEND_LINK receipt: header reads "You sent via link" (not "Sent to Sent via link")
  • Saved-accounts list with a legacy IBAN missing country: placeholder grey bank icon shows (no empty space)

Risk

Surgical: 33 insertions, 12 deletions across 5 files. All changes are NULL-safe optional-chains or additive UI fallbacks; no business logic touched. Pairs with backend PR #675 — that PR makes the API never return details: null; this patch makes the FE robust even if it does.

Companion to peanut-api-ts PR #675. Five FE files patched to
defensively handle the Account shape regressions surfaced by
the staging cutover and to clean up two receipt-rendering bugs.

1. AddWithdrawRouterView.tsx — onAccountClick read
   `account.details.countryName` directly. After the cutover
   `details` was null on every legacy bank account (no
   provider_account_links row). Optional-chain via
   `account.details?.countryName ?? ''` so the click handler
   doesn't crash before the user can pick the account. Backend
   PR #675 also fixes the API to never emit null details, but
   the FE should be defensive in case any path produces null.

2. SavedAccountsView.tsx — `countryCodeForFlag` was conditionally
   rendered, so accounts without a country showed an empty space
   under the bank badge (Hugo screenshotted this). Add a neutral
   grey placeholder with the bank icon so the row reads as
   intentional rather than broken.

3. TransactionDetailsHeaderCard.tsx — the link-transaction
   short-circuit only fired when `(status === pending ||
   cancelled || !userName)`. On `completed` it fell through to
   the generic "Sent to ${displayName}" composition, producing
   "Sent to Sent via link" for completed link sends. Drop the
   gate so link transactions always short-circuit; explicit
   per-status handling for send/receive renders "You sent via
   link" / "You received via link".

4. BankFlowManager.view.tsx — two reads of
   `account.details.countryCode` and one of
   `account.details.accountOwnerName` optional-chained. Same
   defensive pattern.

5. utils/bridge.utils.ts — getCountryFromAccount optional-chains
   on `account.details?.countryCode/countryName`. Same.

All five changes are surgical (33 insertions, 12 deletions) and
pass `pnpm typecheck` + `npm test` (928 tests, 36 suites).
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Apr 29, 2026 7:44am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ab872eba-43b9-4a97-86ea-dffaf52620dd

📥 Commits

Reviewing files that changed from the base of the PR and between 5731934 and df03d69.

📒 Files selected for processing (1)
  • src/utils/bridge.utils.ts

Walkthrough

Null-safe access for account/details and country handling, URL-encoding for withdraw navigation, a fallback UI icon when country flags are missing, and simplified link-transaction title logic that derives titles from direction and completion status.

Changes

Cohort / File(s) Summary
Withdraw routing & encoding
src/components/AddWithdraw/AddWithdrawRouterView.tsx
Compute countryPath safely via optional chaining and fallbacks, set it in withdraw context, and use encodeURIComponent for country and destination query params when navigating to /withdraw/manteca.
Bank flow null-safety
src/components/Claim/Link/views/BankFlowManager.view.tsx
Add optional chaining and default empty-string fallbacks when reading details (e.g., countryCode, accountOwnerName) to avoid runtime errors building bankDetails.
Saved accounts UI fallback
src/components/Common/SavedAccountsView.tsx
Change flag rendering from short-circuit to ternary; when countryCodeForFlag is missing, render a grey circular placeholder with a bank icon instead of nothing.
Transaction header title logic
src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx
Unify link-transaction handling into a dedicated code path regardless of previous status gating; compute header titles from direction and status === 'completed', removing older branch-specific mappings.
Country lookup null-safety
src/utils/bridge.utils.ts
Use optional chaining for account.details; return US immediately for US accounts, otherwise attempt matching by countryName (path) then fallback to matching computed uppercased code against iso3/id.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main changes: fixing post-cutover frontend crashes and receipt label regressions, which directly matches the changeset's focus on null-safety fixes and UI corrections.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, detailing four specific bugs fixed with file-by-file explanations, test plans, and risk assessment that align with the code changes shown.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Review rate limit: 2/5 reviews remaining, refill in 33 minutes and 57 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

Code-analysis diff

Painscore total: 5541.9 → 5543.03 (+1.13)
Findings: 0 net (+14 new, -14 resolved)

🆕 New findings (14)

  • critical complexity — src/components/AddWithdraw/AddWithdrawRouterView.tsx — CC 87, MI 57.96, SLOC 230
  • critical complexity — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx — CC 67, MI 48.08, SLOC 118
  • critical complexity — src/utils/bridge.utils.ts — CC 56, MI 60.85, SLOC 151
  • medium high-mdd — src/components/AddWithdraw/AddWithdrawRouterView.tsx:58 — AddWithdrawRouterView: MDD 105.0 (uses across many lines from declarations)
  • medium high-mdd — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:180 — TransactionDetailsHeaderCard: MDD 41.7 (uses across many lines from declarations)
  • medium high-mdd — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:56 — getTitle: MDD 36.4 (uses across many lines from declarations)
  • medium high-dlt — src/components/AddWithdraw/AddWithdrawRouterView.tsx:58 — AddWithdrawRouterView: DLT 35 (calls 35 distinct functions — high context load)
  • medium high-mdd — src/utils/bridge.utils.ts:180 — inferBankAccountType: MDD 34.8 (uses across many lines from declarations)
  • medium method-complexity — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:56 — CC 29 SLOC 73
  • medium method-complexity — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:180 — CC 21 SLOC 15
  • medium complexity — src/components/Common/SavedAccountsView.tsx — CC 20, MI 63.31, SLOC 57
  • medium method-complexity — src/utils/bridge.utils.ts:180 — CC 20 SLOC 47
  • low high-mdd — src/components/AddWithdraw/AddWithdrawRouterView.tsx:315 — : MDD 16.5 (uses across many lines from declarations)
  • low missing-return-type — src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:180 — TransactionDetailsHeaderCard: exported fn missing return type annotation

✅ Resolved (14)

  • src/components/AddWithdraw/AddWithdrawRouterView.tsx — CC 85, MI 58.12, SLOC 227
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx — CC 72, MI 47.41, SLOC 126
  • src/utils/bridge.utils.ts — CC 55, MI 60.52, SLOC 153
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:56 — CC 34 SLOC 81
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx:58 — AddWithdrawRouterView: MDD 106.8 (uses across many lines from declarations)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:56 — getTitle: MDD 42.9 (uses across many lines from declarations)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:186 — TransactionDetailsHeaderCard: MDD 41.7 (uses across many lines from declarations)
  • src/utils/bridge.utils.ts:179 — inferBankAccountType: MDD 34.8 (uses across many lines from declarations)
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx:58 — AddWithdrawRouterView: DLT 34 (calls 34 distinct functions — high context load)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:186 — CC 21 SLOC 15
  • src/components/Common/SavedAccountsView.tsx — CC 20, MI 63.32, SLOC 57
  • src/utils/bridge.utils.ts:179 — CC 20 SLOC 47
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx:314 — : MDD 16.5 (uses across many lines from declarations)
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx:186 — TransactionDetailsHeaderCard: exported fn missing return type annotation

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

🧪 UI test report — ✅ all green

Suites

  • unit: 932 ran, 0 failed, 0 skipped, 16.1s

📊 Coverage (unit)

metric %
statements 43.0%
branches 22.4%
functions 22.4%
lines 42.7%
⏱ 10 slowest test cases
time test
0.4s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in updateUserById
0.3s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in updateUserById body
0.2s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Manteca PIX form ready shows merchant card + amount input + pay button
0.2s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › Perk claim in progress shows disabled button + progress
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid 9-digit US account
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid Italian IBAN
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle invalid ETH address (too short)
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid US account with spaces 2
0.1s src/app/(mobile-ui)/qr-pay/__tests__/qr-pay-states.test.tsx › SimpleFi WebSocket waiting shows processing indicator
0.1s src/components/Global/GeneralRecipientInput/__tests__/GeneralRecipientInput.test.tsx › should handle valid ETH address with surrounding spaces
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Claim/Link/views/BankFlowManager.view.tsx (1)

259-274: ⚠️ Potential issue | 🔴 Critical

Fix remaining unsafe details dereference in the same null-safety block.

Line 260 still uses addBankAccountResponse.data.details.accountOwnerName directly. If details is null, this path still crashes before the new fallback on Line 273 is useful.

Suggested fix
-                        name: addBankAccountResponse.data.details.accountOwnerName || user?.user.fullName || '',
+                        name: addBankAccountResponse.data.details?.accountOwnerName || user?.user.fullName || '',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/Claim/Link/views/BankFlowManager.view.tsx` around lines 259 -
274, The bankDetails construction still dereferences
addBankAccountResponse.data.details.accountOwnerName unsafely; update the name
assignment in the bankDetails object (the code around bankDetails and
addBankAccountResponse) to use optional chaining and the existing fallbacks
(e.g., addBankAccountResponse.data.details?.accountOwnerName ??
user?.user.fullName ?? '') so the path won’t throw when details is null and
behavior matches the other nullable fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/AddWithdraw/AddWithdrawRouterView.tsx`:
- Around line 221-239: The onAccountClick handler currently sets countryPath
from account.details?.countryName which can be empty and drop the provided
_path; change the fallback so countryPath uses _path when
account.details?.countryName is falsy (e.g., const countryPath =
account.details?.countryName ?? _path ?? ''), then pass that countryPath into
setSelectedMethod and the router.push URL (used when account.type ===
AccountType.MANTECA) so the method state and Manteca URL are always populated.

In `@src/utils/bridge.utils.ts`:
- Around line 168-170: The lookup for countryInfo uses
account.details?.countryName to choose between name-search and code-search but
if the name is present and not found it returns undefined instead of falling
back; change the logic around countryInfo so it first tries
ALL_METHODS_DATA.find by name using account.details?.countryName
(case-insensitive) and, if that result is falsy, then try ALL_METHODS_DATA.find
by id using threeLetterCountryCode (i.e., attempt name match then fallback to
code match), referencing countryInfo, ALL_METHODS_DATA,
account.details?.countryName and threeLetterCountryCode.

---

Outside diff comments:
In `@src/components/Claim/Link/views/BankFlowManager.view.tsx`:
- Around line 259-274: The bankDetails construction still dereferences
addBankAccountResponse.data.details.accountOwnerName unsafely; update the name
assignment in the bankDetails object (the code around bankDetails and
addBankAccountResponse) to use optional chaining and the existing fallbacks
(e.g., addBankAccountResponse.data.details?.accountOwnerName ??
user?.user.fullName ?? '') so the path won’t throw when details is null and
behavior matches the other nullable fields.
🪄 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: 6ec62182-6213-4bfc-b4d6-88d4baff1676

📥 Commits

Reviewing files that changed from the base of the PR and between da39205 and f69ffd1.

📒 Files selected for processing (5)
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx
  • src/components/Claim/Link/views/BankFlowManager.view.tsx
  • src/components/Common/SavedAccountsView.tsx
  • src/components/TransactionDetails/TransactionDetailsHeaderCard.tsx
  • src/utils/bridge.utils.ts

Comment thread src/components/AddWithdraw/AddWithdrawRouterView.tsx Outdated
Comment thread src/utils/bridge.utils.ts Outdated
Per /simplify review of PR #1910. Net -22 lines.

- Drop the 3 inline comment blocks narrating staging history.
- Collapse the 4-case getTitle switch to a lookup map keyed
  on direction. Same behavior, less branching.

928 tests pass.
- AddWithdrawRouterView: use the path arg from SavedAccountsView as
  fallback when account.details.countryName is empty so the Manteca
  withdraw URL doesn't drop country context. Also URL-encode country
  + destination to handle accents/spaces.
- bridge.utils.getCountryFromAccount: if countryName lookup misses
  (legacy 'usa' etc.), fall back to threeLetterCountryCode instead
  of returning undefined.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/utils/bridge.utils.ts`:
- Around line 162-172: The fallback currently compares threeLetterCountryCode
(account.details.countryCode, an ISO3 value) against ALL_METHODS_DATA.id (ISO2),
causing misses; update the lookup in this module so the final return compares
threeLetterCountryCode to ALL_METHODS_DATA entries' iso3 field (c.iso3) and/or
supports both by checking c.iso3 === threeLetterCountryCode || c.id ===
threeLetterCountryCode, keeping the earlier byName lookup intact; update
references around threeLetterCountryCode, ALL_METHODS_DATA.find, and the return
expression to use c.iso3 (and optionally c.id) so non-US accounts resolve
correctly.
🪄 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: e8fd6930-37fd-448f-b6d5-4ed2b9da66fb

📥 Commits

Reviewing files that changed from the base of the PR and between a8a25d2 and 5731934.

📒 Files selected for processing (2)
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx
  • src/utils/bridge.utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/AddWithdraw/AddWithdrawRouterView.tsx

Comment thread src/utils/bridge.utils.ts Outdated
Bridge stores countryCode as ISO3 ('USA', 'GBR') but CountryData.id is
ISO2. The previous fallback `c.id === threeLetterCountryCode` matched
nothing for non-US accounts when the countryName lookup missed. Now
checks both `c.iso3` and `c.id` so the fallback actually fires.
@Hugo0 Hugo0 merged commit f9ad810 into dev Apr 29, 2026
11 of 12 checks 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.

1 participant