Skip to content

Conversation

kushagrasarathe
Copy link
Contributor

@kushagrasarathe kushagrasarathe commented Sep 2, 2025

  • fixes TASK-14380 : always show BIC field in the ui
  • also fixes TASK-14303 : bic required error when auto competition fails
  • also fixes TASK-14104 : remove email field when using sender’s KYC to claim a link
  • also fixes some minor css/ui issues from links v2.1 design qa
  • contributes to TASK-14185 : design qa fixes for links v2.1
  • also contributes to TASK-14186 : design qa fixes for links v2.1

Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Walkthrough

Adds debounced BIC validation and IBAN-driven BIC auto-fill to DynamicBankAccountForm, reorganizes country-flow flags and submit/loading logic, exposes a new hideEmailInput prop, tweaks TokenAmountInput width/alignment, and adjusts a button icon size in DirectRequestInitialView.

Changes

Cohort / File(s) Summary of changes
Add/Withdraw bank form (IBAN/BIC flow)
src/components/AddWithdraw/DynamicBankAccountForm.tsx
Adds useDebounce, debounced BIC validation with loading state, effects to clear submission errors and trigger BIC checks, moves BIC auto-fetch to IBAN blur, inline IBAN validation and country matching, recomputes country flags via useMemo, removes submit-time BIC gating, and adds public prop hideEmailInput?: boolean.
Claim view passing prop
src/components/Claim/Link/views/BankFlowManager.view.tsx
Passes hideEmailInput={true} into DynamicBankAccountForm for BankClaimType.GuestBankClaim flows.
Token amount input UI sizing
src/components/Global/TokenAmountInput/index.tsx
Adjusts dynamic input width calc (use displayValue.length ch, no +1), removes fixed w-[4ch] class, centers text; purely styling/width behavior change.
Direct request initial view
src/components/Request/direct-request/views/Initial.direct.request.view.tsx
Sets iconSize={12} on the final Button (icon="arrow-down-left"); UI-only icon-size tweak.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • jjramirezn
  • Zishan-7
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/bic-autocomplete

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

Remove auto complete BIC

Copy link

@kushagrasarathe kushagrasarathe changed the base branch from feat/bic-debouncing to peanut-wallet-dev September 2, 2025 16:18
@kushagrasarathe kushagrasarathe changed the base branch from peanut-wallet-dev to feat/bic-debouncing September 2, 2025 16:20
@coderabbitai coderabbitai bot added the enhancement New feature or request label Sep 2, 2025
Copy link

vercel bot commented Sep 2, 2025

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

Project Deployment Preview Comments Updated (UTC)
peanut-wallet Ready Ready Preview Comment Sep 3, 2025 10:26am

Copy link
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: 13

Caution

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

⚠️ Outside diff range comments (4)
src/components/TransactionDetails/transactionTransformer.ts (1)

466-472: Guard bankAccountDetails with presence of recipientAccount.

Avoid object construction when recipientAccount is missing.

-        bankAccountDetails:
-            entry.type === EHistoryEntryType.BRIDGE_OFFRAMP ||
-            (entry.type === EHistoryEntryType.BANK_SEND_LINK_CLAIM && entry.userRole === EHistoryUserRole.RECIPIENT)
-                ? {
-                      identifier: entry.recipientAccount.identifier,
-                      type: entry.recipientAccount.type,
-                  }
-                : undefined,
+        bankAccountDetails:
+            entry.recipientAccount &&
+            (entry.type === EHistoryEntryType.BRIDGE_OFFRAMP ||
+                (entry.type === EHistoryEntryType.BANK_SEND_LINK_CLAIM &&
+                    entry.userRole === EHistoryUserRole.RECIPIENT))
+                ? {
+                      identifier: entry.recipientAccount.identifier,
+                      type: entry.recipientAccount.type,
+                  }
+                : undefined,
src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)

100-100: Normalize currency code to uppercase before formatting
getCurrencyConfig returns lowercase codes but formatCurrencyAmount (via getCurrencySymbol) expects uppercase keys—wrap onrampCurrency in .toUpperCase() when calling formatCurrencyAmount.

src/hooks/usePaymentInitiator.ts (1)

769-799: Do not surface backend sync failures for Daimo completion; mark UI success and log instead

Per our learning, Daimo handles success/failure; the backend payment sync should not block UX. Wrap createPayment in a try/catch, keep Success even if syncing fails, and log to Sentry.

       try {
         setLoadingStep('Updating Payment Status')
-        const payment = await chargesApi.createPayment({
+        let payment: PaymentCreationResponse | null = null
+        try {
+          payment = await chargesApi.createPayment({
             chargeId: chargeDetails.uuid,
             chainId: destinationchainId.toString(),
             hash: txHash,
             tokenAddress: chargeDetails.tokenAddress,
             payerAddress,
-            sourceChainId: sourceChainId?.toString(),
+            sourceChainId: String(sourceChainId),
             sourceTokenAddress,
             sourceTokenSymbol,
-        })
-
-        setPaymentDetails(payment)
-        dispatch(paymentActions.setPaymentDetails(payment))
+          })
+          setPaymentDetails(payment)
+          dispatch(paymentActions.setPaymentDetails(payment))
+        } catch (e) {
+          captureException(e)
+          console.warn('Daimo: payment sync failed; proceeding with success UI.')
+        }
 
         setLoadingStep('Success')
         console.log('Daimo payment successful.')
         return { status: 'Success', charge: chargeDetails, payment, txHash, success: true }
       } catch (err) {
         return handleError(err, loadingStep)
       }
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

310-321: IBAN-country mismatch check compares against country name; will false-positive

getCountryFromIban returns ISO-2 code (e.g., 'DE'), but selectedCountry comes from route title (e.g., 'Germany'). Compare to the expected ISO-2 code derived from country instead.

- if (getCountryFromIban(val)?.toLowerCase() !== selectedCountry) {
+ const expectedIso2 = (countryCodeMap[country.toUpperCase()] ?? country.toUpperCase()).toLowerCase()
+ if (getCountryFromIban(val)?.toLowerCase() !== expectedIso2) {
     return 'IBAN does not match the selected country'
   }
🧹 Nitpick comments (21)
src/components/Setup/Views/Welcome.tsx (1)

56-58: Minor: streamline promise handling in click handler

Slightly cleaner and avoids “floating promise” lint warnings.

-                        handleLogin().catch((e) => {
-                            handleError(e)
-                        })
+                        void handleLogin().catch(handleError)
src/components/TransactionDetails/TransactionAvatarBadge.tsx (1)

56-61: Ensure bank icon has sufficient contrast on dark bg

When using AVATAR_TEXT_DARK as background, keep the bank icon fill light; otherwise the icon can blend in.

Apply:

 case 'bank_request_fulfillment':
 case 'bank_claim':
   displayIconName = 'bank'
   displayInitials = undefined
   calculatedBgColor = AVATAR_TEXT_DARK
-  textColor = AVATAR_TEXT_LIGHT
+  textColor = AVATAR_TEXT_LIGHT
+  iconFillColor = AVATAR_TEXT_LIGHT
   break
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)

104-104: Fix small typo in comment

“acitvity” → “activity”.

-                // hide token and network for send links in acitvity drawer for sender
+                // hide token and network for send links in activity drawer for sender
src/utils/__tests__/bridge.utils.test.ts (1)

66-90: Rename test suite to reflect unified API

-describe('getOnrampCurrencyConfig', () => {
+describe('getCurrencyConfig (onramp mode)', () => {
src/app/actions/currency.ts (1)

41-43: Improve error observability.

Include the requested code in the error to ease debugging.

-            default:
-                throw new Error('Unsupported currency')
+            default:
+                throw new Error(`Unsupported currency: ${currencyCode}`)
src/components/TransactionDetails/transactionTransformer.ts (1)

270-281: Extract user-facing strings for i18n consistency.

'Claimed to Bank' appears in multiple branches. Consider centralizing in a constants/i18n file.

src/components/Common/ActionListDaimoPayButton.tsx (2)

125-126: Add peanutWalletAddress to useCallback deps to avoid stale capture

handleCompleteDaimoPayment reads peanutWalletAddress but it’s not listed in dependencies; it can use an outdated address.

Apply:

-        [chargeDetails, completeDaimoPayment, dispatch]
+        [chargeDetails, completeDaimoPayment, dispatch, peanutWalletAddress]

94-107: Retain destinationchainId casing; add null-safety on source fields

  • completeDaimoPayment in usePaymentInitiator.ts:781 expects destinationchainId (lowercase c), so renaming will break the API call.
  • Guard against missing source fields with optional chaining, for example:
-   payerAddress: peanutWalletAddress ?? daimoPaymentResponse.payment.source.payerAddress,
-   sourceChainId: daimoPaymentResponse.payment.source.chainId,
-   sourceTokenAddress: daimoPaymentResponse.payment.source.tokenAddress,
-   sourceTokenSymbol: daimoPaymentResponse.payment.source.tokenSymbol,
+   payerAddress: peanutWalletAddress ?? daimoPaymentResponse?.payment?.source?.payerAddress,
+   sourceChainId: daimoPaymentResponse?.payment?.source?.chainId,
+   sourceTokenAddress: daimoPaymentResponse?.payment?.source?.tokenAddress,
+   sourceTokenSymbol: daimoPaymentResponse?.payment?.source?.tokenSymbol,
src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)

55-57: Avoid recomputing config + symbol inline.

Minor perf/readability: extract a small helper to get onramp currency, then reuse.

Apply within-range change:

-    return getCurrencySymbol(getCurrencyConfig(requestFulfilmentSelectedCountry?.id ?? 'US', 'onramp').currency)
+    return getCurrencySymbol(getOnrampCurrency(requestFulfilmentSelectedCountry?.id))

Add this helper near the imports (or top of file):

const getOnrampCurrency = (countryId?: string) =>
  getCurrencyConfig(countryId ?? 'US', 'onramp').currency
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)

336-340: Memoize onrampCurrency and pass real rate if available

  • Compute onrampCurrency once via useMemo([selectedCountry.id]) and use it for both code and symbol instead of calling getCurrencyConfig twice.
  • Optionally replace the hard-coded price: 1 with the actual on-ramp rate (when available) so TokenAmountInput can display correct FIAT↔TOKEN conversions.
src/hooks/useCurrency.ts (4)

36-46: Avoid stale updates; set symbol immediately to reduce UI flicker.

  • Pre-set the symbol before fetching so UI can render while loading.
  • Guard state updates if the effect is cleaned up.

Apply:

-        setIsLoading(true)
-        getCurrencyPrice(code)
+        setIsLoading(true)
+        setSymbol(SIMBOLS_BY_CURRENCY_CODE[code])
+        let cancelled = false
+        getCurrencyPrice(code)
             .then((price) => {
-                setSymbol(SIMBOLS_BY_CURRENCY_CODE[code])
-                setPrice(price)
-                setIsLoading(false)
+                if (cancelled) return
+                setPrice(price)
+                setIsLoading(false)
             })
             .catch((err) => {
-                console.error(err)
-                setIsLoading(false)
+                if (cancelled) return
+                console.error(err)
+                setIsLoading(false)
             })
+        return () => {
+            cancelled = true
+        }

30-33: Use constant-membership check instead of Object.keys().includes().

Cheaper and clearer.

-        if (!Object.keys(SIMBOLS_BY_CURRENCY_CODE).includes(code)) {
+        if (!(code in SIMBOLS_BY_CURRENCY_CODE)) {

43-46: Clear stale values on failure.

If fetch fails, retain prior symbol/price, which can mislead UI. Reset them.

             .catch((err) => {
                 console.error(err)
+                setSymbol(null)
+                setPrice(null)
                 setIsLoading(false)
             })

7-8: Typo: SIMBOLS → SYMBOLS.

Rename SIMBOLS_BY_CURRENCY_CODE to SYMBOLS_BY_CURRENCY_CODE for clarity (update references).

src/hooks/usePaymentInitiator.ts (3)

791-798: Type-cleanup: avoid optional chaining on a required number

sourceChainId is typed as number; remove ?. to avoid masking bugs and be explicit.

-        sourceChainId: sourceChainId?.toString(),
+        sourceChainId: String(sourceChainId),

771-773: Consistent naming: destinationChainId (camelCase)

Minor readability nit: use destinationChainId everywhere.

-      destinationchainId,
+      destinationChainId,
...
-      destinationchainId: number
+      destinationChainId: number

And update the reference at payment payload chainId accordingly.


810-811: Fix stale closures in useCallback deps

completeDaimoPayment reads dispatch, handleError, and loadingStep; include them in deps and drop unused determineChargeDetails.

-    [determineChargeDetails, setLoadingStep, setPaymentDetails]
+    [dispatch, setLoadingStep, setPaymentDetails, handleError, loadingStep]
src/components/Claim/Link/views/Confirm.bank-claim.view.tsx (2)

57-61: Guard formatUnits against undefined decimals and non-bigint input

formatUnits expects value and decimals; harden to avoid runtime errors on edge data.

-const usdAmount = useMemo(
-  () => formatUnits(claimLinkData?.amount ?? 0, claimLinkData?.tokenDecimals) || '0.00',
+const usdAmount = useMemo(
+  () =>
+    formatUnits(
+      BigInt(claimLinkData?.amount ?? 0),
+      claimLinkData?.tokenDecimals ?? 18
+    ) || '0.00',
   [claimLinkData]
 )

70-93: Make amount formatting robust and consistent

Avoid NaN and ensure consistent formatting with Intl.NumberFormat; fall back cleanly.

-const displayAmount = useMemo(() => {
-  if (currencyCode === 'USD') return usdAmount
-  if (isLoadingCurrency) return '-'
-  if (!price || isNaN(price)) return usdAmount
-  const converted = (Number(usdAmount) * price).toFixed(2)
-  return converted
-}, [price, usdAmount, currencyCode, isLoadingCurrency])
+const displayAmount = useMemo(() => {
+  const n = Number(usdAmount)
+  if (!Number.isFinite(n)) return usdAmount
+  const v = currencyCode === 'USD' || !price ? n : n * price
+  return new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(v)
+}, [price, usdAmount, currencyCode])

Display symbol fallback logic looks good.

src/components/AddWithdraw/DynamicBankAccountForm.tsx (2)

350-377: BIC validation UX and naming nit

Validation flow is solid; minor: rename setter to setIsCheckingBICValid for consistency.

-const [isCheckingBICValid, setisCheckingBICValid] = useState(false)
+const [isCheckingBICValid, setIsCheckingBICValid] = useState(false)
...
- setisCheckingBICValid(true)
+ setIsCheckingBICValid(true)
...
- setisCheckingBICValid(false)
+ setIsCheckingBICValid(false)

297-348: Autocomplete hint for account/IBAN fields

Add autoComplete="bank-account-number" to IBAN/account number inputs to help browsers/wallets.

Example:

-  'text',
+  'text',
+  undefined,
+  undefined,
+  { autoComplete: 'bank-account-number' }

(You may need to extend renderInput to accept inputProps and spread them into BaseInput.)

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 367bff2 and 54699de.

📒 Files selected for processing (28)
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (2 hunks)
  • src/app/actions/currency.ts (1 hunks)
  • src/app/actions/onramp.ts (3 hunks)
  • src/components/AddMoney/components/AddMoneyBankDetails.tsx (2 hunks)
  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx (1 hunks)
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx (5 hunks)
  • src/components/Claim/Claim.tsx (1 hunks)
  • src/components/Claim/Link/Initial.view.tsx (2 hunks)
  • src/components/Claim/Link/views/BankFlowManager.view.tsx (3 hunks)
  • src/components/Claim/Link/views/Confirm.bank-claim.view.tsx (3 hunks)
  • src/components/Common/ActionList.tsx (2 hunks)
  • src/components/Common/ActionListDaimoPayButton.tsx (1 hunks)
  • src/components/Global/PeanutActionDetailsCard/index.tsx (4 hunks)
  • src/components/Request/views/ReqFulfillBankFlowManager.tsx (4 hunks)
  • src/components/Setup/Views/Welcome.tsx (2 hunks)
  • src/components/TransactionDetails/TransactionAvatarBadge.tsx (1 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (3 hunks)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1 hunks)
  • src/components/TransactionDetails/transactionTransformer.ts (2 hunks)
  • src/constants/actionlist.consts.ts (2 hunks)
  • src/hooks/useCreateOnramp.ts (3 hunks)
  • src/hooks/useCurrency.ts (1 hunks)
  • src/hooks/usePaymentInitiator.ts (2 hunks)
  • src/services/charges.ts (2 hunks)
  • src/utils/__tests__/bridge.utils.test.ts (1 hunks)
  • src/utils/bridge.utils.ts (0 hunks)
  • src/utils/index.ts (0 hunks)
  • src/utils/onramp.utils.ts (0 hunks)
💤 Files with no reviewable changes (3)
  • src/utils/onramp.utils.ts
  • src/utils/index.ts
  • src/utils/bridge.utils.ts
🧰 Additional context used
🧠 Learnings (15)
📚 Learning: 2025-08-26T17:38:37.055Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/components/Common/ActionList.tsx:153-156
Timestamp: 2025-08-26T17:38:37.055Z
Learning: In ActionList.tsx, when there are circular dependency concerns with ACTION_METHODS being imported by other components, the preferred solution is to move ACTION_METHODS to a separate constants file (like src/constants/actionlist.consts.ts) rather than using prop drilling. This centralizes constants management and creates a cleaner dependency graph.

Applied to files:

  • src/constants/actionlist.consts.ts
  • src/components/Common/ActionList.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.

Applied to files:

  • src/components/Claim/Link/Initial.view.tsx
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-01-16T13:14:40.363Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.

Applied to files:

  • src/components/Claim/Link/Initial.view.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.

Applied to files:

  • src/components/Claim/Link/Initial.view.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.

Applied to files:

  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
  • src/components/AddMoney/components/AddMoneyBankDetails.tsx
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Applied to files:

  • src/components/AddWithdraw/AddWithdrawCountriesList.tsx
  • src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
  • src/components/Request/views/ReqFulfillBankFlowManager.tsx
📚 Learning: 2024-11-18T21:36:11.486Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.

Applied to files:

  • src/components/Claim/Claim.tsx
📚 Learning: 2024-10-18T01:51:35.247Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:141-141
Timestamp: 2024-10-18T01:51:35.247Z
Learning: The `handleConfirm` function in `src/components/Create/Link/Confirm.view.tsx` is separate from the one in `src/components/Offramp/Confirm.view.tsx` and does not need to be renamed when refactoring `handleConfirm` in `src/components/Offramp/Confirm.view.tsx`.

Applied to files:

  • src/components/Claim/Link/views/BankFlowManager.view.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.328Z
Learning: In `src/components/Common/ActionListDaimoPayButton.tsx`, the `handleCompleteDaimoPayment` function should not display error messages to users when DB update fails because the Daimo payment itself has succeeded - showing errors would be confusing since the payment was successful.

Applied to files:

  • src/components/Common/ActionListDaimoPayButton.tsx
📚 Learning: 2025-08-22T07:28:32.281Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.281Z
Learning: In `src/components/Payment/PaymentForm/index.tsx`, the `handleCompleteDaimoPayment` function is only for updating payment status in the backend after a successful Daimo payment. Payment success/failure is handled by Daimo itself, so try/catch error handling and error display are not needed for backend sync failures - users shouldn't see errors if payment succeeded but database update failed.

Applied to files:

  • src/components/Common/ActionListDaimoPayButton.tsx
  • src/hooks/usePaymentInitiator.ts
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.

Applied to files:

  • src/components/Common/ActionListDaimoPayButton.tsx
📚 Learning: 2025-08-12T17:47:28.362Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1089
File: src/app/api/bridge/exchange-rate/route.ts:4-19
Timestamp: 2025-08-12T17:47:28.362Z
Learning: In the Bridge exchange rate API route (src/app/api/bridge/exchange-rate/route.ts), the ExchangeRateResponse interface uses numeric types for rates because the route converts string values from the Bridge API to floats using parseFloat() before returning the response.

Applied to files:

  • src/app/actions/currency.ts
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.

Applied to files:

  • src/app/actions/currency.ts
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2024-11-26T12:06:11.603Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
🧬 Code graph analysis (14)
src/components/Claim/Link/views/BankFlowManager.view.tsx (1)
src/services/sendLinks.ts (1)
  • sendLinksApi (88-228)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)
src/utils/bridge.utils.ts (2)
  • getCurrencyConfig (13-33)
  • getCurrencySymbol (45-52)
src/components/Common/ActionList.tsx (1)
src/constants/actionlist.consts.ts (1)
  • ACTION_METHODS (13-39)
src/hooks/usePaymentInitiator.ts (1)
src/services/services.types.ts (1)
  • TRequestChargeResponse (172-210)
src/components/Claim/Link/views/Confirm.bank-claim.view.tsx (2)
src/hooks/useCurrency.ts (1)
  • useCurrency (11-55)
src/utils/bridge.utils.ts (1)
  • getCurrencySymbol (45-52)
src/components/Setup/Views/Welcome.tsx (1)
src/utils/general.utils.ts (1)
  • getFromLocalStorage (126-148)
src/hooks/useCurrency.ts (1)
src/app/actions/currency.ts (1)
  • getCurrencyPrice (7-50)
src/app/actions/onramp.ts (2)
src/utils/bridge.utils.ts (1)
  • getCurrencyConfig (13-33)
src/app/actions/currency.ts (1)
  • getCurrencyPrice (7-50)
src/app/actions/currency.ts (2)
src/app/actions/exchange-rate.ts (1)
  • getExchangeRate (25-61)
src/utils/sentry.utils.ts (1)
  • fetchWithSentry (11-89)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (2)
src/utils/bridge-accounts.utils.ts (1)
  • validateIban (36-38)
src/app/actions/ibanToBic.ts (1)
  • getBicFromIban (10-17)
src/components/Global/PeanutActionDetailsCard/index.tsx (2)
src/app/[...recipient]/loading.tsx (1)
  • Loading (3-5)
src/constants/zerodev.consts.ts (1)
  • PEANUT_WALLET_TOKEN_SYMBOL (21-21)
src/components/Request/views/ReqFulfillBankFlowManager.tsx (2)
src/hooks/useCreateOnramp.ts (1)
  • useCreateOnramp (24-78)
src/components/Common/CountryListRouter.tsx (1)
  • CountryListRouter (38-173)
src/hooks/useCreateOnramp.ts (3)
src/components/AddMoney/consts/index.ts (1)
  • CountryData (139-147)
src/utils/bridge.utils.ts (1)
  • getCurrencyConfig (13-33)
src/app/actions/currency.ts (1)
  • getCurrencyPrice (7-50)
src/utils/__tests__/bridge.utils.test.ts (2)
src/utils/bridge.utils.ts (1)
  • getCurrencyConfig (13-33)
src/utils/index.ts (1)
  • getCurrencyConfig (11-11)
🔇 Additional comments (26)
src/components/AddWithdraw/AddWithdrawCountriesList.tsx (1)

3-3: Unused import removal — LGTM

countryCodeMap is not referenced in this file. Safe cleanup.

src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)

100-108: Token/Network row gating — LGTM

Good call hiding for sender-side SEND_LINK entries in history to reduce noise.

src/components/TransactionDetails/TransactionCard.tsx (1)

29-30: Add bank_claim across type, icon, and label — LGTM

Consistent handling with other claim/withdraw flows.

Also applies to: 239-242, 263-266

src/app/actions/currency.ts (1)

7-9: No action needed: unstable_cache keys by function arguments
unstable_cache in Next.js 14.2+ automatically includes serializable function arguments in its cache key, so per-currency results are cached separately as expected. Remove the verification comment.

Likely an incorrect or invalid review comment.

src/services/charges.ts (1)

68-71: Verify backend supports extended payload
Ensure the createPayment handler in src/services/charges.ts (and its backend counterpart) accepts and forwards sourceChainId, sourceTokenAddress, and sourceTokenSymbol to avoid 4xx errors.

src/components/Claim/Link/views/BankFlowManager.view.tsx (2)

106-115: Associate claim: non-blocking + Sentry capture is correct

Good call to associate the claim to the user without blocking the success path; errors are logged to Sentry and ignored so UX isn’t impacted.


31-31: Deps updated; import scoped correctly

Importing sendLinksApi and adding user to the dependency array keeps handleConfirmClaim reactive to auth changes.

Also applies to: 127-127

src/components/Claim/Link/Initial.view.tsx (2)

115-121: Reset flow on anon→authenticated transition: LGTM

prevUser-based guard avoids unnecessary resets and only triggers when a user logs in.


784-785: Gate GuestVerificationModal to guests only

Changing isOpen to showVerificationModal && !user aligns with intent and prevents confusing modals for logged-in users.

src/components/Claim/Claim.tsx (1)

216-224: Auth gating logic clarified; confirm no UI flicker

Allowing immediate claim when no user, and deferring sender checks until isFetchingUser is false, is reasonable. Given checkLink re-runs on user changes, the state should settle correctly.

Please sanity-check on slow networks to ensure linkState doesn’t briefly flip between CLAIM and CLAIM_SENDER during auth resolution.

Also applies to: 231-231

src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)

16-16: Unified currency config import — looks good.

Consistent with the move to bridge.utils. No concerns.

src/app/actions/onramp.ts (2)

6-8: Currency config/price imports — aligned.

Matches the unified API. Good.


78-81: Rename and guard the local amount variable, update payload, and confirm currency units

         const { currency, paymentRail } = getCurrencyConfig(params.country.id, 'onramp')
         const price = await getCurrencyPrice(currency)
-        const amount = (Number(params.amount) * price).toFixed(2)
+        const inputAmt = Number(params.amount)
+        if (!Number.isFinite(inputAmt)) {
+            return { error: 'Invalid amount' }
+        }
+        const currencyAmount = (inputAmt * price).toFixed(2)
@@
-                amount,
+                amount: currencyAmount,

Confirm the backend expects the local-currency “amount” (EUR/MXN) field, not USD or token units. Applies also to lines 89–96.

src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)

26-26: Consolidated currency helpers — ok.

src/components/Global/PeanutActionDetailsCard/index.tsx (3)

13-13: Loading import — good.


202-227: Do not remove the $ fallback until every bank-account callsite passes currencySymbol. None of the current <PeanutActionDetailsCard> usages include a currencySymbol prop—removing this fallback will break the display in bank-account and claim-link success flows. Either ensure all these callsites supply currencySymbol first or keep the $ fallback.


49-50: Verify isLoading at all usages
All 14 <PeanutActionDetailsCard> call sites currently omit the new isLoading prop—ensure you pass isLoading={true} when the underlying data is loading or rely on its default (false).

src/components/Common/ActionList.tsx (2)

121-132: Sorting available methods first — clean and memoized.

Immutably copies ACTION_METHODS before sort; comparator is clear. LGTM.


157-170: Rendering with sortedActionMethods — good integration.

Bank remains clickable when verification is required (to trigger the flow), while “soon” stays disabled. Matches UX intent.

src/hooks/useCreateOnramp.ts (2)

36-39: Confirm Bridge API currency code casing: getCurrencyConfig returns lowercase codes. I didn’t find any existing source.currency usages—verify the Bridge API docs to see if it requires uppercase codes and, if so, normalize via currency.toUpperCase().


48-56: Confirm API amount type
File src/hooks/useCreateOnramp.ts (lines 48–56): We currently send amount: currencyAmount (string). Verify that /api/proxy/bridge/onramp/create expects a string; if it expects a number, convert currencyAmount (e.g., Number(currencyAmount)).

src/components/Request/views/ReqFulfillBankFlowManager.tsx (1)

161-162: Copy update looks good.

“Where to pay from?” reads clearer for the country selection context.

src/hooks/usePaymentInitiator.ts (1)

775-778: Approve code changes
Forwarding sourceChainId/sourceTokenAddress/sourceTokenSymbol aligns with the chargesApi.createPayment signature.

src/components/Claim/Link/views/Confirm.bank-claim.view.tsx (2)

16-18: Good addition: currency utilities wiring

useCurrency/getCurrencySymbol imports make the display adaptive.


106-110: Prop pass-through looks correct

amount/displaySymbol/isLoading are wired into PeanutActionDetailsCard as intended.

src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

401-407: Submit gating looks right

Disabling on isSubmitting/!isValid/isCheckingBICValid prevents premature submits.

@kushagrasarathe kushagrasarathe changed the base branch from feat/bic-debouncing to peanut-wallet-dev September 3, 2025 09:35
@kushagrasarathe kushagrasarathe changed the title [WIP] fix: always show BIC input in ui fix: always show BIC input in ui Sep 3, 2025
@kushagrasarathe kushagrasarathe requested review from Zishan-7 and removed request for Zishan-7 September 3, 2025 09:42
Copy link
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/AddWithdraw/DynamicBankAccountForm.tsx (1)

312-317: Compare country codes consistently for IBAN-country match

selectedCountry may be a title; getCountryFromIban likely returns ISO2. Compare ISO2 codes derived from both sides to avoid false negatives.

-                                            if (getCountryFromIban(val)?.toLowerCase() !== selectedCountry) {
+                                            const ibanIso2 = getCountryFromIban(val)?.toLowerCase()
+                                            const selectedIso2 = countryCodeMap[country.toUpperCase()]?.toLowerCase()
+                                            if (ibanIso2 && selectedIso2 && ibanIso2 !== selectedIso2) {
                                                 return 'IBAN does not match the selected country'
                                             }
♻️ Duplicate comments (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

63-66: Normalize US detection once and reuse; avoid 'US' misclassification and duplicate logic

Compute country flags once (supporting both 'USA' and 'US'), derive a single countryCodeForApi, and reuse inside onSubmit. This also removes duplicate flag recomputation.

Apply:

-        const isMx = country.toUpperCase() === 'MX'
-        const isUs = country.toUpperCase() === 'USA'
-        const isIban = isUs || isMx ? false : isIBANCountry(country)
+        const UPPER_COUNTRY = country.toUpperCase()
+        const isUs = UPPER_COUNTRY === 'USA' || UPPER_COUNTRY === 'US'
+        const isMx = UPPER_COUNTRY === 'MX'
+        const isIban = !isUs && !isMx && isIBANCountry(UPPER_COUNTRY)
+        const countryCodeForApi = isUs ? 'USA' : UPPER_COUNTRY
-                const isUs = country.toUpperCase() === 'USA'
-                const isMx = country.toUpperCase() === 'MX'
-                const isIban = isUs || isMx ? false : isIBANCountry(country)
+                // reuse top-level isUs/isMx/isIban
-                    countryCode: isUs ? 'USA' : country.toUpperCase(),
+                    countryCode: countryCodeForApi,
-                        country: isUs ? 'USA' : country.toUpperCase(),
+                        country: countryCodeForApi,

Also applies to: 140-143, 159-159, 171-171

🧹 Nitpick comments (3)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (3)

73-73: Setter naming nit: use camelCase for state setter

Align with React conventions for readability.

-        const [isCheckingBICValid, setisCheckingBICValid] = useState(false)
+        const [isCheckingBICValid, setIsCheckingBICValid] = useState(false)

And update usages:

- setisCheckingBICValid(true)
- setisCheckingBICValid(false)
+ setIsCheckingBICValid(true)
+ setIsCheckingBICValid(false)

Also applies to: 364-366, 405-406


111-117: Effect dependency fix: react to BIC changes, not getValues ref

Use debouncedBicValue in the dependency array and condition.

-            if (submissionError && isValid && (!isIban || getValues('bic'))) {
+            if (submissionError && isValid && (!isIban || debouncedBicValue?.trim())) {
                 setSubmissionError(null)
             }
-        }, [isValid, submissionError, isIban, getValues])
+        }, [isValid, submissionError, isIban, debouncedBicValue])

297-305: Add autocomplete hint for account number inputs

Per prior learning, hint browsers to assist entry for IBAN/US/CLABE.

-        const renderInput = (
+        const renderInput = (
             name: keyof IBankAccountDetails,
             placeholder: string,
             rules: any,
             type: string = 'text',
             rightAdornment?: React.ReactNode,
-            onBlur?: (field: any) => Promise<void> | void
+            onBlur?: (field: any) => Promise<void> | void,
+            autoComplete?: string
         ) => (
@@
-                            <BaseInput
+                            <BaseInput
                                 {...field}
                                 type={type}
                                 placeholder={placeholder}
                                 className="h-12 w-full rounded-sm border border-n-1 bg-white px-4 text-sm"
+                                autoComplete={autoComplete}

Apply to IBAN/US/CLABE account numbers:

-                            ? renderInput('clabe', 'CLABE', {
+                            ? renderInput('clabe', 'CLABE', {
                                   required: 'CLABE is required',
                                   ...
-                              })
+                              }, 'text', undefined, undefined, 'bank-account-number')
@@
-                              ? renderInput(
+                              ? renderInput(
                                     'accountNumber',
                                     'IBAN',
                                     {
                                       ...
                                     },
                                     'text',
-                                    undefined,
+                                    undefined,
                                     async (field) => { ... }
-                                )
+                                , 'bank-account-number')
@@
-                              : renderInput(
+                              : renderInput(
                                     'accountNumber',
                                     'Account Number',
                                     {
                                       ...
                                     },
-                                    'text'
+                                    'text',
+                                    undefined,
+                                    undefined,
+                                    'bank-account-number'
                                 )}

Also applies to: 340-348, 200-207, 215-231

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between edb7e58 and 9f0f2f1.

📒 Files selected for processing (1)
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx (8 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2024-11-26T12:06:11.603Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
🧬 Code graph analysis (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (3)
src/hooks/useDebounce.ts (1)
  • useDebounce (9-23)
src/utils/bridge-accounts.utils.ts (2)
  • validateIban (36-38)
  • validateBic (73-89)
src/app/actions/ibanToBic.ts (1)
  • getBicFromIban (10-17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

324-336: Good safeguard: don’t overwrite user-entered BIC; validate after auto-fill

Only setting BIC when empty and validating is the right UX.

Copy link

Copy link

Copy link

Copy link
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: 0

Caution

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

⚠️ Outside diff range comments (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

79-85: Add trigger to destructured form methods

You'll need to add trigger to the destructured methods from useForm to support the suggested BIC validation improvements.

 const {
     control,
     handleSubmit,
     setValue,
     getValues,
     watch,
+    trigger,
     formState: { errors, isValid, isValidating, touchedFields },
 } = useForm<IBankAccountDetails>({
♻️ Duplicate comments (3)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (3)

65-67: Country classification inconsistency

The isUs check includes only 'USA' but should also handle 'US' for consistency with the rest of the codebase. This can cause misclassification if 'US' is provided as input.

Apply this fix to handle both 'USA' and 'US':

-const isUs = country.toUpperCase() === 'USA'
+const isUs = country.toUpperCase() === 'USA' || country.toUpperCase() === 'US'

368-370: Missing error recovery in BIC validation

The BIC validation doesn't guarantee that setisCheckingBICValid(false) is called if validateBic throws an error, which could leave the form in a permanently disabled state.

Wrap the validation in a try-finally block:

-setisCheckingBICValid(true)
-const isValid = await validateBic(value.trim())
-setisCheckingBICValid(false)
-return isValid || 'Invalid BIC code'
+setisCheckingBICValid(true)
+try {
+    const isValid = await validateBic(value.trim())
+    return isValid || 'Invalid BIC code'
+} finally {
+    setisCheckingBICValid(false)
+}

120-126: BIC validation race condition vulnerability

The current implementation has a race condition where rapid submit clicks can bypass BIC validation. The form currently returns true in the validate function until the debounced value stabilizes, allowing submission before actual validation completes.

Replace setValue with trigger in the debounce effect and add pre-submit validation:

 // Trigger BIC validation when debounced value changes
 useEffect(() => {
     if (isIban && debouncedBicValue && debouncedBicValue.trim().length > 0) {
-        // Trigger validation for the BIC field
-        setValue('bic', debouncedBicValue, { shouldValidate: true })
+        // Validate without mutating field value
+        trigger('bic')
     }
-}, [debouncedBicValue, isIban, setValue])
+}, [debouncedBicValue, isIban, trigger])

Also add validation enforcement before submission at line 140:

 setIsSubmitting(true)
+// Enforce BIC validation just before submit for IBAN flows
+if (isIban) {
+    const isValidBic = await trigger('bic')
+    if (!isValidBic) {
+        setIsSubmitting(false)
+        return
+    }
+}
 try {
🧹 Nitpick comments (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

409-410: Consider preventing submit while BIC is being typed

The submit button can be clicked while the user is still typing in the BIC field (before debounce completes), potentially causing validation race conditions.

Add an additional check to disable the button when BIC input doesn't match the debounced value:

-disabled={isSubmitting || !isValid || isCheckingBICValid}
+disabled={
+    isSubmitting ||
+    !isValid ||
+    isCheckingBICValid ||
+    (isIban && bicValue?.trim() !== debouncedBicValue?.trim())
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9f0f2f1 and aabaf6e.

📒 Files selected for processing (2)
  • src/components/AddWithdraw/DynamicBankAccountForm.tsx (11 hunks)
  • src/components/Claim/Link/views/BankFlowManager.view.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/components/Claim/Link/views/BankFlowManager.view.tsx
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/utils/withdraw.utils.ts:181-191
Timestamp: 2025-08-14T14:42:54.411Z
Learning: The countryCodeMap in src/components/AddMoney/consts/index.ts uses uppercase 3-letter country codes as keys (like 'AUT', 'BEL', 'CZE') that map to 2-letter country codes, requiring input normalization to uppercase for proper lookups.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
📚 Learning: 2024-11-26T12:06:11.603Z
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#545
File: src/components/Global/GeneralRecipientInput/index.tsx:118-126
Timestamp: 2024-11-26T12:06:11.603Z
Learning: For bank account input fields, use `autocomplete="bank-account-number"` when the recipient type is `'us'` or `'iban'`.

Applied to files:

  • src/components/AddWithdraw/DynamicBankAccountForm.tsx
🧬 Code graph analysis (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (3)
src/hooks/useDebounce.ts (1)
  • useDebounce (9-23)
src/utils/bridge-accounts.utils.ts (2)
  • validateIban (36-38)
  • validateBic (73-89)
src/app/actions/ibanToBic.ts (1)
  • getBicFromIban (10-17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Deploy-Preview
🔇 Additional comments (1)
src/components/AddWithdraw/DynamicBankAccountForm.tsx (1)

330-340: LGTM! Auto-fill BIC with proper empty check

The implementation correctly auto-fills BIC only when the field is empty and triggers validation after setting the value, preventing overwriting user-entered values.

@kushagrasarathe kushagrasarathe merged commit 263ca62 into peanut-wallet-dev Sep 4, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants