Skip to content

Conversation

Zishan-7
Copy link
Contributor

@Zishan-7 Zishan-7 commented Aug 26, 2025

Contributes to tasks -
TASK-14251
TASK-14252
TASK-14247
TASK-14248
TASK-14250
TASK-14253

Please note - Cross chain txn bug fix (TASK-14254) will only work after the backend PR is merged

Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

Walkthrough

Adds Daimo payment flow updates: new store fields and actions, revised API for tracking deposit tx with extra fields, integration of a new ActionList DaimoPay button using function-as-children in DaimoPayButton, PaymentForm cleanup to remove Daimo UI, support for DEPOSIT in success view, minor UI/layout tweaks, config option, and dependency bump.

Changes

Cohort / File(s) Summary of changes
Daimo deposit flow and success view
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx, src/components/Payment/Views/Status.payment.view.tsx
Page calls trackDaimoDepositTransactionHash with object {txHash,payerAddress,sourceChainId,sourceTokenAddress}; DirectSuccessView type set to "DEPOSIT" and key fixed; Status view adds "DEPOSIT" type support and header path.
Users action API update
src/app/actions/users.ts
trackDaimoDepositTransactionHash signature changed to single object param adding sourceChainId and sourceTokenAddress; request payload expanded; error handling pattern unchanged.
Payment state additions and usage
src/redux/slices/payment-slice.ts, src/redux/types/payment.types.ts, src/app/[...recipient]/client.tsx
Adds daimoError and isDaimoPaymentProcessing to state; new actions setDaimoError and setIsDaimoPaymentProcessing; client uses isDaimoPaymentProcessing to extend loading condition.
Action list refactor and Daimo button integration
src/components/Common/ActionList.tsx, src/components/Common/ActionListDaimoPayButton.tsx, src/components/Global/DaimoPayButton/index.tsx
ActionList switches to external ACTION_METHODS/PaymentMethod and renders ActionListDaimoPayButton for 'exchange-or-wallet'; new ActionListDaimoPayButton component initiates/completes Daimo payments and wires modal callbacks; DaimoPayButton supports function-as-children and adds helper onClick/validation text updates.
New action list constants
src/constants/actionlist.consts.ts
Adds PaymentMethod interface and ACTION_METHODS with Bank, Mercado Pago, Exchange/Wallet items and their icons.
Payment form cleanup and Daimo error UI
src/components/Payment/PaymentForm/index.tsx
Removes DaimoPayButton integration and handlers; reads daimoError from store and renders dedicated alert; clears both general and Daimo errors on recipient change; syncs USD amount to Redux.
Minor UI and layout tweaks
src/components/Common/CountryList.tsx, src/components/TransactionDetails/TransactionCard.tsx, src/components/AddMoney/components/CryptoMethodDrawer.tsx, src/components/UserHeader/index.tsx
CountryList title conditional for deposit/withdraw; TransactionCard name container flex behavior adjusted; Drawer adds extra bottom padding; UserHeader formats address-like names using printableAddress.
Config update
src/config/wagmi.config.tsx
DaimoPayProvider options include disableMobileInjector: true.
Dependency bump
package.json
@daimo/pay version bumped from ^1.15.0 to ^1.16.5.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested reviewers

  • kushagrasarathe
  • jjramirezn

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ 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/daimo-bugs

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 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

vercel bot commented Aug 26, 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 Aug 27, 2025 7:33am

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: 8

Caution

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

⚠️ Outside diff range comments (3)
src/components/Common/CountryList.tsx (1)

89-101: Remove non-null assertion on flow to avoid runtime crash

flow is optional in props; calling onCryptoClick(flow!) risks an exception if a caller forgets to pass it in add-withdraw mode.

- onClick={() => onCryptoClick(flow!)}
+ onClick={() => flow && onCryptoClick(flow)}

For stronger safety, see the discriminated-union props suggestion below.

src/components/Global/DaimoPayButton/index.tsx (1)

71-101: Guard against empty/NaN/negative amounts before showing Daimo.

If children is a render-prop and the consumer ignores the disabled flag, handleButtonClick can still invoke show() with an empty or invalid amount. Add strict validation in handleClick to prevent that and return a clear error.

Apply:

-    const handleClick = useCallback(async () => {
-        // Parse and validate amount
-        const formattedAmount = parseFloat(amount.replace(/,/g, ''))
+    const handleClick = useCallback(async () => {
+        // Sanitize and validate amount
+        const sanitized = amount.replace(/,/g, '').trim()
+        const formattedAmount = Number(sanitized)
+
+        if (!sanitized) {
+            onValidationError?.('Please enter an amount.')
+            return false
+        }
+        if (!Number.isFinite(formattedAmount) || formattedAmount <= 0) {
+            onValidationError?.('Amount must be a positive number.')
+            return false
+        }
...
-        await resetPayment({
-            toUnits: amount.replace(/,/g, ''),
-        })
+        await resetPayment({
+            toUnits: sanitized,
+        })
 
         return true
-    }, [amount, minAmount, maxAmount, onValidationError, onBeforeShow, resetPayment])
+    }, [amount, minAmount, maxAmount, onValidationError, onBeforeShow, resetPayment])
src/app/[...recipient]/client.tsx (1)

528-533: Fix grammar in user-facing error copy.

“The payment” instead of “They payment”.

Apply:

-    message: 'They payment you are trying to access is invalid. Please check the URL and try again.',
+    message: 'The payment you are trying to access is invalid. Please check the URL and try again.',
🧹 Nitpick comments (13)
src/config/wagmi.config.tsx (1)

82-85: Optional: avoid recreating the options object on each render

Minor render optimization: memoize the options object to prevent unnecessary subtree updates.

Add above the return inside ContextProvider:

const daimoOptions = useMemo(() => ({ embedGoogleFonts: true, disableMobileInjector: true }), [])

Then change these lines:

- <DaimoPayProvider
-   options={{ embedGoogleFonts: true, disableMobileInjector: true }}
-   customTheme={DAIMO_THEME}
- >
+ <DaimoPayProvider options={daimoOptions} customTheme={DAIMO_THEME}>
src/components/TransactionDetails/TransactionCard.tsx (2)

111-116: Guard currency symbol resolution for undefined/varied casing codes

getDisplayCurrencySymbol(actualCurrencyCode) may receive undefined or mixed-case values. Normalize to uppercase and add a safe fallback.

- : transaction.currencySymbol || getDisplayCurrencySymbol(actualCurrencyCode) // Use provided sign+symbol or derive symbol
+ : transaction.currencySymbol ||
+   (actualCurrencyCode ? getDisplayCurrencySymbol(actualCurrencyCode.toUpperCase()) : '')

123-128: Token decimals selection is tied to SEND_LINK only

Decimals fall back to tokenDecimalsForDisplay only when originalType === SEND_LINK. This risks inconsistent display for DIRECT_SEND or other token flows.

Prefer reading a generic decimals hint (e.g., transaction.extraDataForDrawer?.tokenDecimalsForDisplay) regardless of originalType, with sensible defaults:

- const decimalsForDisplay = actualCurrencyCode
-   ? defaultDisplayDecimals
-   : transaction.extraDataForDrawer?.originalType === EHistoryEntryType.SEND_LINK
-     ? ((transaction.extraDataForDrawer as any)?.tokenDecimalsForDisplay ?? 6)
-     : 6
+ const decimalsForDisplay = actualCurrencyCode
+   ? defaultDisplayDecimals
+   : Number((transaction.extraDataForDrawer as any)?.tokenDecimalsForDisplay) || 6
src/components/Common/CountryList.tsx (3)

89-89: Copy nit: consider “Add with Crypto” for consistency with “Add/Withdraw”

“Crypto Deposit” reads fine, but “Add with Crypto” may align better with the rest of the flow naming (Add/Withdraw). Your call.


46-54: Normalize country codes to uppercase when checking geo match

countryCodeMap uses uppercase 3-letter keys; normalize a.id before lookup to avoid misses. This matches how you already do it later at lines 105–107.

- const aIsUserCountry =
-   countryCodeMap[a.id] === userGeoLocationCountryCode || a.id === userGeoLocationCountryCode
- const bIsUserCountry =
-   countryCodeMap[b.id] === userGeoLocationCountryCode || b.id === userGeoLocationCountryCode
+ const aIsUserCountry =
+   countryCodeMap[a.id.toUpperCase()] === userGeoLocationCountryCode ||
+   a.id.toUpperCase() === userGeoLocationCountryCode
+ const bIsUserCountry =
+   countryCodeMap[b.id.toUpperCase()] === userGeoLocationCountryCode ||
+   b.id.toUpperCase() === userGeoLocationCountryCode

14-20: Make props types safer with a discriminated union

In add-withdraw mode, flow and onCryptoClick should be required; the current optional typing forces runtime checks. A discriminated union encodes this at compile time.

Example:

type AddWithdrawProps = {
  inputTitle: string
  viewMode: 'add-withdraw'
  onCountryClick: (country: CountryData) => void
  onCryptoClick: (flow: 'add' | 'withdraw') => void
  flow: 'add' | 'withdraw'
}

type ClaimRequestProps = {
  inputTitle: string
  viewMode: 'claim-request'
  onCountryClick: (country: CountryData) => void
}

type CountryListViewProps = AddWithdrawProps | ClaimRequestProps

I can open a follow-up PR to apply this change across call sites if you’d like.

src/redux/types/payment.types.ts (1)

20-22: Hide backend‐sync failures from the user and clarify Daimo error semantics

  • Initial state is correctly set in src/redux/slices/payment-slice.ts (lines 25–26):

      daimoError: null,
      isDaimoPaymentProcessing: false,

    (no action needed here)

  • In src/components/Payment/PaymentForm/index.tsx (around lines 775–777), the UI still does:

    {daimoError && <ErrorAlert description={daimoError} />}
    {!daimoError && error && ()}

    This surfaces backend‐sync failures as a Daimo payment error—per our prior learning, users shouldn’t see sync‐only errors when the payment itself succeeded. Instead:
    • Remove or suppress the <ErrorAlert> for daimoError in the form UI
    • Log or report daimoError in the background without interrupting the user flow

  • Add a brief TSDoc comment on IPaymentState in src/redux/types/payment.types.ts to explain:
    error: payment‐processing failures (e.g. card decline)
    daimoError: backend update (sync) failures only

  • (Optional) Consider renaming daimoError to daimoSyncError (or similar) to make this distinction obvious in code and avoid confusion with the generic error field.

src/components/Payment/Views/Status.payment.view.tsx (2)

176-176: Hide recipient label/link for deposit flows

DEPOSIT is a self-funding event; showing a recipient can confuse users. Gate the recipient snippet out when type === 'DEPOSIT'.

- {!isExternalWalletFlow &&
-   !isWithdrawFlow &&
-   (recipientType !== 'USERNAME' ? (
+ {!isExternalWalletFlow &&
+   !isWithdrawFlow &&
+   type !== 'DEPOSIT' &&
+   (recipientType !== 'USERNAME' ? (
      <AddressLink
        className="text-sm font-normal text-grey-1 no-underline"
        address={recipientName}
      />
     ) : (
       recipientName
     ))}

91-139: Receipt construction currently hardcodes a SEND context

transactionForDrawer is populated with direction: 'send' and originalType: DIRECT_SEND. It’s fine since the “See receipt” button is SEND-only, but consider guarding this block with if (type === 'SEND') to avoid future confusion.

Example:

const transactionForDrawer = useMemo(() => {
  if (!chargeDetails || type !== 'SEND') return null
  // ... existing construction
}, [chargeDetails, type, /* ... */])
src/components/UserHeader/index.tsx (1)

65-73: Simplify: rely on printableAddress and drop duplicate isAddress/useMemo.

printableAddress already no-ops for non-address strings, so the explicit isAddress + useMemo is redundant. This reduces imports and render logic without changing behavior.

Apply:

-    const isCryptoAddress = useMemo(() => {
-        return isAddress(name)
-    }, [name])
...
-            <div className={twMerge('text-sm font-semibold md:text-base', className)}>
-                {isCryptoAddress ? printableAddress(name, 4, 4) : name}
-            </div>
+            <div className={twMerge('text-sm font-semibold md:text-base', className)}>
+                {printableAddress(name, 4, 4)}
+            </div>

And remove unused imports:

-import { useMemo } from 'react'
-import { isAddress } from 'viem'
 import { printableAddress } from '@/utils'
src/components/Global/DaimoPayButton/index.tsx (1)

104-107: Avoid hard-throwing on missing NEXT_PUBLIC_DAIMO_APP_ID in client.

Throwing here will crash the page at runtime if the env is absent/misconfigured. Consider rendering nothing and logging an error (or showing a user-facing message) to keep the rest of the UI functional.

Example:

-    if (!daimoAppId) {
-        throw new Error('Daimo APP ID is required')
-    }
+    if (!daimoAppId) {
+        console.error('Daimo APP ID is required')
+        onValidationError?.('We’re setting up deposits. Please try again in a bit.')
+        return null
+    }
src/app/actions/users.ts (1)

135-137: Consider validating new fields for consistency

While txHash and payerAddress are validated, the new fields sourceChainId and sourceTokenAddress are not checked. Consider adding validation for these fields as well to ensure data integrity.

-        if (!txHash || !payerAddress) {
-            throw new Error('Missing required fields: txHash and payerAddress')
+        if (!txHash || !payerAddress || !sourceChainId || !sourceTokenAddress) {
+            throw new Error('Missing required fields: txHash, payerAddress, sourceChainId, and sourceTokenAddress')
         }
src/components/Common/ActionListDaimoPayButton.tsx (1)

63-63: Remove or conditionally include console.log statements

Production code should not contain console.log statements. Consider using a debug flag or removing these entirely.

-        console.log('Initiating Daimo payment', payload)
+        if (process.env.NODE_ENV === 'development') {
+            console.log('Initiating Daimo payment', payload)
+        }
📜 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 7239eab and c4af3cc.

📒 Files selected for processing (15)
  • src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (2 hunks)
  • src/app/[...recipient]/client.tsx (2 hunks)
  • src/app/actions/users.ts (2 hunks)
  • src/components/AddMoney/components/CryptoMethodDrawer.tsx (1 hunks)
  • src/components/Common/ActionList.tsx (4 hunks)
  • src/components/Common/ActionListDaimoPayButton.tsx (1 hunks)
  • src/components/Common/CountryList.tsx (1 hunks)
  • src/components/Global/DaimoPayButton/index.tsx (3 hunks)
  • src/components/Payment/PaymentForm/index.tsx (8 hunks)
  • src/components/Payment/Views/Status.payment.view.tsx (2 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (1 hunks)
  • src/components/UserHeader/index.tsx (2 hunks)
  • src/config/wagmi.config.tsx (1 hunks)
  • src/redux/slices/payment-slice.ts (2 hunks)
  • src/redux/types/payment.types.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/components/Global/DaimoPayButton/index.tsx
  • src/redux/types/payment.types.ts
  • src/components/Common/ActionList.tsx
  • src/app/[...recipient]/client.tsx
  • src/components/Payment/PaymentForm/index.tsx
  • src/redux/slices/payment-slice.ts
  • src/app/(mobile-ui)/add-money/crypto/direct/page.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/Common/CountryList.tsx
  • src/app/(mobile-ui)/add-money/crypto/direct/page.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/Common/CountryList.tsx
📚 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/components/Common/ActionList.tsx
  • src/components/Payment/PaymentForm/index.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/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-06-18T19:56:55.443Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#919
File: src/components/Withdraw/views/Initial.withdraw.view.tsx:87-87
Timestamp: 2025-06-18T19:56:55.443Z
Learning: In withdraw flows for Peanut Wallet, the PeanutActionDetailsCard should always display "USDC" as the token symbol because it shows the amount being withdrawn from the Peanut Wallet (which holds USDC), regardless of the destination token/chain selected by the user. The TokenSelector is used for choosing the withdrawal destination, not the source display.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-22T07:25:59.258Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.258Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🧬 Code graph analysis (8)
src/config/wagmi.config.tsx (1)
src/constants/daimo.consts.ts (1)
  • DAIMO_THEME (1-101)
src/components/Common/ActionListDaimoPayButton.tsx (7)
src/redux/hooks.ts (2)
  • useAppDispatch (5-5)
  • usePaymentStore (12-12)
src/components/Common/ActionList.tsx (1)
  • ACTION_METHODS (38-64)
src/hooks/useCurrency.ts (1)
  • useCurrency (9-42)
src/hooks/usePaymentInitiator.ts (2)
  • usePaymentInitiator (80-831)
  • InitiatePaymentPayload (52-68)
src/redux/slices/payment-slice.ts (1)
  • paymentActions (81-81)
src/components/Global/DaimoPayButton/index.tsx (1)
  • DaimoPayButton (51-163)
src/components/SearchUsers/SearchResultCard.tsx (1)
  • SearchResultCard (19-70)
src/components/Global/DaimoPayButton/index.tsx (2)
src/components/Global/Icons/Icon.tsx (1)
  • IconName (62-120)
src/components/0_Bruddle/Button.tsx (1)
  • Button (76-267)
src/app/[...recipient]/client.tsx (1)
src/redux/hooks.ts (1)
  • usePaymentStore (12-12)
src/components/Payment/PaymentForm/index.tsx (2)
src/hooks/usePaymentInitiator.ts (1)
  • usePaymentInitiator (80-831)
src/redux/slices/payment-slice.ts (1)
  • paymentActions (81-81)
src/components/UserHeader/index.tsx (1)
src/utils/general.utils.ts (1)
  • printableAddress (70-73)
src/components/Payment/Views/Status.payment.view.tsx (1)
src/components/Global/SoundPlayer.tsx (1)
  • SoundPlayer (18-30)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (1)
src/app/actions/users.ts (1)
  • trackDaimoDepositTransactionHash (123-165)
⏰ 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 (25)
src/config/wagmi.config.tsx (2)

82-85: LGTM: DaimoPayProvider options update fits the new Daimo flow

Adding disableMobileInjector: true alongside embedGoogleFonts: true looks consistent with the custom DAIMO_THEME (Roboto/Inter). No API surface changes and provider ordering remains sane.


82-85: Double-check global application of disableMobileInjector & embedGoogleFonts in DaimoPayProvider

I didn’t find any environment- or device-based gating around these options—they’re applied unconditionally in src/config/wagmi.config.tsx (lines 82–85).

Please verify the following manually to ensure no degradation in UX or redundant font loading:

  • Wallet connection & checkout flows on
    • iOS Safari
    • iOS Chrome
  • Wallet connection & checkout flows on
    • Android Chrome
    • In-app browsers (e.g. Telegram, Twitter)
  • That Roboto (or other Google fonts) isn’t being double-loaded if Next.js is preloading them; disable embedGoogleFonts if necessary
src/components/Common/CountryList.tsx (1)

85-101: All “add-withdraw” CountryList instances include the flow prop

I’ve checked every CountryList usage with viewMode="add-withdraw" and confirmed they all pass flow (e.g. in AddWithdrawRouterView.tsx at lines 231–238). No further changes needed here.

src/components/Payment/Views/Status.payment.view.tsx (2)

30-31: LGTM: DirectSuccessView now supports a DEPOSIT type

Extending the type union is clean and isolates DEPOSIT behavior without altering SEND/REQUEST semantics.


182-192: Confirm mobile header behavior for DEPOSIT and REQUEST

You added NavHeader for SEND and DEPOSIT. If REQUEST success screens should also expose a back action on mobile, consider including REQUEST here for parity; otherwise, confirm this difference is intentional.

src/components/UserHeader/index.tsx (1)

8-11: printableAddress correctly re-exported from utils barrel

The barrel file src/utils/index.ts includes the line

export * from './general.utils'

which ensures that printableAddress is available from @/utils. No import path changes are required.

src/components/Global/DaimoPayButton/index.tsx (1)

111-117: Verify DaimoPayButton prop semantics

Please double-check against the official @daimo/pay documentation or type definitions to ensure:

  • The intent prop value is exactly "Deposit" (capital “D”) and matches one of the accepted values in DaimoPayButton.Custom (e.g. "Deposit" | "Withdraw" | …).
  • The toUnits prop expects a human-readable decimal string (e.g. "1234.56") rather than atomic units (e.g. "1234560000000000000"). If it requires atomic units, apply the proper conversion (e.g. multiply by 10^decimals).

No definitive source was found in the current codebase—please verify in the upstream package or its published type definitions.

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

27-27: LGTM: additional bottom padding improves scroll/safe-area spacing.

This is a sensible UI tweak for drawer content that may have sticky/overlapping CTAs.

src/app/[...recipient]/client.tsx (1)

45-47: Payment Slice: isDaimoPaymentProcessing Properly Integrated

All set—isDaimoPaymentProcessing is correctly defined, defaults to false, and is wired through the slice:

  • Type definition added at src/redux/types/payment.types.ts:21
  • Default state set to false at src/redux/slices/payment-slice.ts:26
  • Action creator setIsDaimoPaymentProcessing implemented at src/redux/slices/payment-slice.ts:72–73

No further changes needed.

src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (3)

27-33: Server-tracking call shape updated — matches new API.

Good use of an object payload including sourceChainId and sourceTokenAddress. The catch-and-continue behavior aligns with the past learning that users shouldn’t see errors if the backend sync fails after a successful Daimo payment.


50-51: LGTM: success view correctly uses DEPOSIT type.

This aligns with the new DirectSuccessView support for deposits.


22-39: trackDaimoDepositTransactionHash is already a server-only action

I checked src/app/actions/users.ts and confirmed:

  • The very first line is 'use server', so everything in this file—including trackDaimoDepositTransactionHash and its use of process.env.PEANUT_API_KEY!—runs only on the server and is never bundled to the client.
  • Your client component (page.tsx) can safely import and call this server action without exposing the API key.

No changes are needed here.

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

28-28: Good separation of concerns for Daimo payment flow

The extraction of Daimo payment logic into a dedicated component ActionListDaimoPayButton improves modularity and makes the code more maintainable.


38-38: Export made public for reusability

Making ACTION_METHODS public is appropriate since it's now consumed by ActionListDaimoPayButton. This follows the principle of exposing what's needed while maintaining encapsulation.


126-126: Refactored amount calculation to avoid potential NaN

Good defensive programming - using ternary operator usdAmount ? parseFloat(usdAmount) : 0 prevents NaN when usdAmount is null/undefined.


183-196: Clean integration of DaimoPayButton component

The conditional rendering logic is well-structured. The special case for 'exchange-or-wallet' method is cleanly separated, while preserving the existing MethodCard behavior for other payment methods.

src/redux/slices/payment-slice.ts (2)

25-26: State initialization for Daimo error handling

Properly initialized new state fields for Daimo error and processing status tracking.


69-74: Well-implemented Redux actions for Daimo state management

The new reducers follow Redux best practices with appropriate typing and immutable state updates. This provides a clean interface for managing Daimo payment state across components.

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

123-133: Improved function signature with destructured parameters

The refactored signature using destructured object parameters is cleaner and more maintainable. This approach makes the function call more explicit and reduces the chance of parameter ordering errors.

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

136-145: Verify disabled state logic

The SearchResultCard is disabled when either loading or isProcessing is true, but both values might represent the same state. Consider if this duplication is necessary.

Can you verify if loading (from the render prop) and isProcessing represent different states? If they're always synchronized, you might only need one.


27-30: Add explicit null check for parseFloat

The current check parseFloat(usdAmount) <= 0 could throw an error if usdAmount is null. Consider adding explicit null checking before parsing.

-        if (!usdAmount || parseFloat(usdAmount) <= 0) {
+        if (!usdAmount || isNaN(parseFloat(usdAmount)) || parseFloat(usdAmount) <= 0) {
             console.error('Invalid amount entered')
             return false
         }
⛔ Skipped due to learnings
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#868
File: src/components/Payment/PaymentForm/index.tsx:284-293
Timestamp: 2025-05-19T19:40:43.138Z
Learning: When converting between USD and token amounts, always check if the token price (divisor) is valid and non-zero before performing the division to prevent Infinity, NaN, or errors. Implementing validation like `if (!tokenPrice || isNaN(tokenPrice) || tokenPrice === 0)` before division operations is crucial for handling cases where price data might be unavailable.
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1098
File: src/components/LandingPage/noFees.tsx:26-26
Timestamp: 2025-08-15T08:04:31.171Z
Learning: In the peanut-ui codebase, URL parameter parsing with parseFloat() for numeric values is considered safe due to: 1) parseFloat() only returns numbers/NaN (no executable code), 2) comprehensive validation exists elsewhere in the codebase, 3) values flow through type-safe React components, and 4) no direct DOM manipulation occurs that could expose XSS vectors.
src/components/Payment/PaymentForm/index.tsx (4)

83-83: Good addition of Daimo error state tracking

Extracting daimoError from the payment store enables separate handling of Daimo-specific errors.


182-183: Consistent error clearing on recipient change

Good practice to clear both general and Daimo-specific errors when the recipient changes or component mounts.

Also applies to: 187-187


698-701: Good practice: Redux state synchronization

Setting both local state and Redux state for USD amount ensures consistency across the application.


775-785: Clean error display hierarchy

The conditional rendering of Daimo errors separately from general errors provides clear user feedback. The fallback message for insufficient balance is user-friendly.

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: 1

Caution

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

⚠️ Outside diff range comments (5)
src/components/TransactionDetails/TransactionCard.tsx (2)

80-83: Bug: completed non-USD bank_deposit shows USD with wrong decimals

When a non-USD bank_deposit is completed, you display USD but still use defaultDisplayDecimals derived from the original currency. For JPY-origin deposits, this renders USD with 0 decimals (e.g., $123 instead of $123.00). Use USD’s decimals in this branch.

Apply:

         if (isCompleted) {
-            // For completed transactions: show USD amount (amount is already in USD)
-            finalDisplayAmount = `$${formatNumberForDisplay(Math.abs(amount).toString(), { maxDecimals: defaultDisplayDecimals })}`
+            // For completed transactions: show USD amount (display in USD conventions)
+            const usdDecimals = 2
+            finalDisplayAmount = `$${formatNumberForDisplay(Math.abs(amount).toString(), { maxDecimals: usdDecimals })}`
         } else {

140-141: Ensure clickable Card is keyboard-accessible and correctly announced

The Card component currently renders as a plain <div> with an onClick handler but no ARIA or keyboard support. To meet accessibility requirements, update it so that whenever onClick is provided, the Card:

  • Is focusable (tabIndex={0})
  • Announces itself as a button (role="button")
  • Responds to Enter and Space keys by invoking onClick
  • Optionally reflects disabled state with aria-disabled if you add a disabled prop

Locations to update:

  • File: src/components/Global/Card/index.tsx
  • Line: the <div> returned in the component’s return block

Suggested diff snippet:

--- a/src/components/Global/Card/index.tsx
+++ b/src/components/Global/Card/index.tsx
@@ -38,7 +38,17 @@ const Card: React.FC<CardProps> = ({ children, position = 'single', className 
     return (
-        <div
+        <div
             className={twMerge('w-full bg-white px-4 py-2', getBorderRadius(), getBorder(), className)}
-            onClick={onClick}
+            onClick={onClick}
+            /* Make clickable div accessible */
+            role={onClick ? 'button' : undefined}
+            tabIndex={onClick ? 0 : undefined}
+            onKeyDown={onClick ? (e) => {
+              if (e.key === 'Enter' || e.key === ' ') {
+                e.preventDefault()
+                onClick()
+              }
+            } : undefined}
         >
             {children}
         </div>

With these changes, a keyboard user can focus the Card, activate it via Enter/Space, and assistive technologies will treat it as a button.

src/components/Payment/PaymentForm/index.tsx (3)

285-291: Bug: Prefill writes USD into token input

When price data is fetched, the code sets inputTokenAmount to the computed USD value. TokenAmountInput.tokenValue expects a token-denominated amount, not USD. This will mislabel the amount, break validations, and later conversions.

Fix by setting the USD state(s) and keeping the original token amount in inputTokenAmount:

-                        // calculate USD value
-                        const tokenAmount = parseFloat(requestDetails.tokenAmount)
-                        const usdValue = formatAmount(tokenAmount * priceData.price)
-                        setInputTokenAmount(usdValue)
-                        setUsdValue(usdValue)
+                        // calculate USD value
+                        const tokenAmount = parseFloat(requestDetails.tokenAmount)
+                        const usdValue = formatAmount(tokenAmount * priceData.price)
+                        // keep token input in token units
+                        setInputTokenAmount(requestDetails.tokenAmount)
+                        // update USD states so downstream logic and UI are in sync
+                        setInputUsdValue(usdValue)
+                        setUsdValue(usdValue)

415-422: Harden cross-token conversion: normalize chainId types and handle empty USD

Two issues here:

  • requestedChain !== selectedChainID is type-sensitive (string vs number) and may incorrectly trigger conversion.
  • Conversion relies solely on inputUsdValue. When it's empty (e.g., prefilled flows), parseFloat('') becomes NaN, yielding tokenAmount = 'NaN'.

Normalize types and fall back to usdValue:

-        if (
-            requestedToken &&
-            requestedTokenPrice &&
-            (requestedChain !== selectedChainID || !areEvmAddressesEqual(requestedToken, selectedTokenAddress))
-        ) {
-            tokenAmount = (parseFloat(inputUsdValue) / requestedTokenPrice).toString()
-        }
+        if (
+            requestedToken &&
+            requestedTokenPrice &&
+            (String(requestedChain) !== String(selectedChainID) ||
+                !areEvmAddressesEqual(requestedToken, selectedTokenAddress))
+        ) {
+            const effectiveUsd = inputUsdValue && parseFloat(inputUsdValue) > 0 ? inputUsdValue : usdValue
+            tokenAmount = (parseFloat(effectiveUsd) / requestedTokenPrice).toString()
+        }

Also add usdValue to the callback deps to keep it consistent:

   }, [
       canInitiatePayment,
-      isDepositRequest,
       isConnected,
       openReownModal,
       recipient,
       inputTokenAmount,
       isPintaReq,
       requestId,
       initiatePayment,
       beerQuantity,
       chargeDetails,
       isExternalWalletFlow,
       requestDetails,
       selectedTokenAddress,
       selectedChainID,
       inputUsdValue,
       requestedTokenPrice,
+      usdValue,
   ])

552-555: Align insufficient-balance detection with actual error messages

Local checks set 'Insufficient balance' / 'Insufficient balance in connected wallet', while this predicate looks for “You don't have enough balance.” The mismatch can suppress intended behaviors (e.g., Add Money CTA).

Short-term, match both strings (case-insensitive). Longer-term, move to an error code on the store to avoid brittle string checks.

-    const isInsufficientBalanceError = useMemo(() => {
-        return error?.includes("You don't have enough balance.")
-    }, [error])
+    const isInsufficientBalanceError = useMemo(() => {
+        const msg = (error || '').toLowerCase()
+        return (
+            msg.includes("you don't have enough balance") ||
+            msg.includes('insufficient balance')
+        )
+    }, [error])
♻️ Duplicate comments (3)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (1)

48-48: Fix confirmed; optional simplification for key prop.

The extra brace bug is resolved. You can simplify by using a plain string instead of a template literal.

Apply:

-                key={`success-add-money`}
+                key="success-add-money"
src/components/TransactionDetails/TransactionCard.tsx (1)

175-175: Great fix: truncation now works inside flex containers

Switching to "min-w-0 flex-1 truncate" prevents the left column from pushing the amount and enables proper ellipsis. Matches the earlier recommendation.

src/components/Payment/PaymentForm/index.tsx (1)

771-781: Gate Daimo error display to only user-actionable validation

Per prior guidance, post-success DB update failures must not surface to users. Show Daimo errors only for actionable preflight validations (e.g., min/max deposit). If you don’t yet have a code on daimoError, defensively filter by known validation patterns and prefer moving to typed error codes.

Change the render to a guarded flag:

-                    {daimoError && <ErrorAlert description={daimoError} />}
+                    {shouldShowDaimoError && <ErrorAlert description={daimoError} />}

Add this memo near other memos:

const shouldShowDaimoError = useMemo(() => {
    if (!daimoError) return false
    // Temporary heuristic until error codes are plumbed through:
    return (
        daimoError.includes('Maximum deposit') ||
        daimoError.includes('Minimum deposit')
    )
}, [daimoError])

Longer-term: carry a structured { code: 'DAIMO_MIN_DEPOSIT' | 'DAIMO_MAX_DEPOSIT' | 'DAIMO_BACKEND_SYNC_FAILED', message: string } in Redux and branch on code.

🧹 Nitpick comments (11)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (5)

27-32: Harden payload extraction and coerce chainId to string.

  • Robustify against unexpected event shapes to avoid TypeErrors.
  • trackDaimoDepositTransactionHash expects string fields; chainId may arrive as a number from providers—coerce to string to satisfy typing and avoid backend ambiguity.

Apply:

-            await trackDaimoDepositTransactionHash({
-                txHash: e.txHash,
-                payerAddress: e.payment.source.payerAddress,
-                sourceChainId: e.payment.source.chainId,
-                sourceTokenAddress: e.payment.source.tokenAddress,
-            })
+            const txHash = e?.txHash
+            const payerAddress = e?.payment?.source?.payerAddress
+            const sourceChainId =
+                e?.payment?.source?.chainId != null ? String(e.payment.source.chainId) : ''
+            const sourceTokenAddress = e?.payment?.source?.tokenAddress
+            await trackDaimoDepositTransactionHash({
+                txHash,
+                payerAddress,
+                sourceChainId,
+                sourceTokenAddress,
+            })

22-22: Replace any with a minimal event type for compile-time safety.

Annotate the Daimo completion event to document the contract and catch regressions.

Example:

-export default function AddMoneyCryptoDirectPage() {
+type DaimoPaymentCompletedEvent = {
+  txHash: string
+  payment: { source: { payerAddress: string; chainId: string | number; tokenAddress: string } }
+}
+export default function AddMoneyCryptoDirectPage() {
...
-    const onPaymentCompleted = async (e: any) => {
+    const onPaymentCompleted = async (e: DaimoPaymentCompletedEvent) => {

51-51: Standardize currency formatting.

Render a properly formatted currency string to keep UX consistent and avoid cases like “$0.1”.

Apply:

-                currencyAmount={`$${inputTokenAmount}`}
+                currencyAmount={new Intl.NumberFormat(undefined, {
+                    style: 'currency',
+                    currency: 'USD',
+                    minimumFractionDigits: 2,
+                    maximumFractionDigits: 2,
+                }).format(Number(inputTokenAmount || 0))}

41-43: Consider not gating the success UI on the backend update.

Per prior Daimo learnings, the DB sync should not affect user-facing success. You could show the success view immediately and fire-and-forget the tracking call (with logging), improving perceived latency.

Option: remove the loading branch and set isPaymentSuccess(true) before awaiting the tracking call, or trigger the tracking in a non-blocking void promise with error capture.


18-18: Setter name casing nit.

Rename setisPaymentSuccess to setIsPaymentSuccess to match common React naming conventions.

Apply:

-    const [isPaymentSuccess, setisPaymentSuccess] = useState(false)
+    const [isPaymentSuccess, setIsPaymentSuccess] = useState(false)
...
-            setisPaymentSuccess(true)
+            setIsPaymentSuccess(true)

Also applies to: 37-37

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

123-128: Use tokenDecimalsForDisplay whenever available (not only for SEND_LINK)

Decimal precision for tokens should respect tokenDecimalsForDisplay regardless of originalType. This avoids unexpected 6-decimal truncation for other token flows.

-        const decimalsForDisplay = actualCurrencyCode // If it's a known currency (USD, ARS)
-            ? defaultDisplayDecimals
-            : transaction.extraDataForDrawer?.originalType === EHistoryEntryType.SEND_LINK // Example: check token specific decimals if available
-              ? ((transaction.extraDataForDrawer as any)?.tokenDecimalsForDisplay ?? 6) // Fallback to 6 for tokens
-              : 6 // General fallback for other tokens
+        const decimalsForDisplay = actualCurrencyCode
+            ? defaultDisplayDecimals
+            : ((transaction.extraDataForDrawer as any)?.tokenDecimalsForDisplay ?? 6)

129-134: Avoid re-prefixing symbol when appending token symbol

finalDisplayAmount already contains the symbol (or none for tokens). Re-appending displaySymbol is redundant.

-        finalDisplayAmount = `${displaySymbol}${formatNumberForDisplay(amountString, { maxDecimals: decimalsForDisplay })}`
+        finalDisplayAmount = `${displaySymbol}${formatNumberForDisplay(amountString, { maxDecimals: decimalsForDisplay })}`
         if (!isStableCoin && !actualCurrencyCode) {
             // Append token symbol if it's a token transaction
-
-            finalDisplayAmount = `${displaySymbol}${finalDisplayAmount} ${transaction.tokenSymbol}`
+            finalDisplayAmount = `${finalDisplayAmount} ${transaction.tokenSymbol}`
         }

151-153: Improve avatar image alt text for accessibility

If the avatar is decorative (name is adjacent), prefer empty alt to avoid redundant announcements. If you want it announced, use a descriptive alt.

-                                    alt="Icon"
+                                    alt=""
src/components/Payment/PaymentForm/index.tsx (3)

139-140: Remove unused isDepositRequest and its dependency to reduce churn

The value isn’t used in handleInitiatePayment and being in the deps causes unnecessary callback re-creation.

Apply this cleanup:

-    const isDepositRequest = searchParams.get('action') === 'deposit'

And remove it from the deps:

-        isDepositRequest,

Also applies to: 454-472


524-528: De-duplicate beer-quantity effects

Two effects update beerQuantity from inputTokenAmount under the same condition. Keep one to avoid double-dispatch and make behavior easier to reason about.

Also applies to: 544-550


145-148: Trim unused dep in isConnected memo

status is included in the dependency list but not used in the calculation. Removing it will prevent unnecessary recomputation.

📜 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 c4af3cc and 27978d5.

📒 Files selected for processing (5)
  • src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (2 hunks)
  • src/components/Common/ActionListDaimoPayButton.tsx (1 hunks)
  • src/components/Global/DaimoPayButton/index.tsx (3 hunks)
  • src/components/Payment/PaymentForm/index.tsx (5 hunks)
  • src/components/TransactionDetails/TransactionCard.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Common/ActionListDaimoPayButton.tsx
  • src/components/Global/DaimoPayButton/index.tsx
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/app/(mobile-ui)/add-money/crypto/direct/page.tsx
  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-26T15:25:53.301Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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/app/(mobile-ui)/add-money/crypto/direct/page.tsx
  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.

Applied to files:

  • src/app/(mobile-ui)/add-money/crypto/direct/page.tsx
📚 Learning: 2025-07-07T20:22:11.092Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#958
File: src/app/actions/tokens.ts:266-266
Timestamp: 2025-07-07T20:22:11.092Z
Learning: In `src/app/actions/tokens.ts`, within the `fetchWalletBalances` function, using the non-null assertion operator `!` on `process.env.MOBULA_API_KEY!` is intentional and correct, and should not be flagged for replacement with explicit validation.

Applied to files:

  • src/app/(mobile-ui)/add-money/crypto/direct/page.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/Payment/PaymentForm/index.tsx
📚 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/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-22T07:25:59.258Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.258Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🧬 Code graph analysis (2)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (1)
src/app/actions/users.ts (1)
  • trackDaimoDepositTransactionHash (123-165)
src/components/Payment/PaymentForm/index.tsx (2)
src/hooks/usePaymentInitiator.ts (1)
  • usePaymentInitiator (80-831)
src/redux/slices/payment-slice.ts (1)
  • paymentActions (81-81)
⏰ 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 (4)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (2)

50-50: DEPOSIT type usage looks correct.

Assuming DirectSuccessViewProps includes "DEPOSIT" (as per related changes), this aligns the success view with the deposit flow.


47-55: Check DirectSuccessView header logic to avoid unintended overrides

I’ve verified that the DirectSuccessView props include both a type?: 'SEND' | 'REQUEST' | 'DEPOSIT' and an optional headerTitle?: string, and that the component uses:

  • Its own type-based defaults (e.g. “You deposited”) when headerTitle is not provided
  • Always the passed-in headerTitle when it is provided

Since our mobile page explicitly passes headerTitle="Add Money" alongside type="DEPOSIT", this will replace the DEPOSIT default (“You deposited”) with “Add Money.”
Please confirm that “Add Money” is indeed the desired header for deposit flows on mobile. If we intend to keep the type-specific copy, remove the headerTitle prop here so that the component’s built-in default is used instead.

src/components/Payment/PaymentForm/index.tsx (2)

80-86: Good: Scoped Daimo error in store is now plumbed into the form

Pulling daimoError from the store here makes the UI react to Daimo-specific issues independently of the generic error. This separation is the right direction.


694-697: Good: Keep Redux USD state in sync with user input

Updating both local state and paymentActions.setUsdAmount here ensures downstream consumers have the latest USD value without waiting for the initiator flow. Matches prior learnings about passing decimal strings upstream.

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 (5)
src/components/Payment/PaymentForm/index.tsx (5)

551-553: Insufficient-balance detection is broken due to string mismatch; fix detection and alert copy

You set "Insufficient balance" earlier but check for "You don't have enough balance." here, so the CTA never flips to “Add funds,” and the retry copy logic doesn't trigger. Use a robust, case-insensitive check (or better: a typed error), and update the alert mapping accordingly.

Apply this diff:

@@
-    const isInsufficientBalanceError = useMemo(() => {
-        return error?.includes("You don't have enough balance.")
-    }, [error])
+    const isInsufficientBalanceError = useMemo(() => {
+        const msg = (error ?? '').toLowerCase()
+        // Matches both "Insufficient balance" and "Insufficient balance in connected wallet"
+        return msg.includes('insufficient balance')
+    }, [error])
@@
-                    {!daimoError && error && (
+                    {!daimoError && error && (
                         <ErrorAlert
                             description={
-                                error.includes("You don't have enough balance.")
+                                (error ?? '').toLowerCase().includes('insufficient balance')
                                     ? 'Not enough balance to fulfill this request with Peanut'
                                     : error
                             }
                         />
                     )}

Also applies to: 775-779


739-753: CTA is hidden for external-wallet flows; remove Peanut-only gating

Both the primary and Retry CTAs render only when the Peanut Wallet is connected. In external-wallet flows (Add Money, non-Peanut sends), this hides the only action and blocks progression. Render the CTA regardless of Peanut wallet status; your button text/disable logic already adapts per state.

Apply this diff:

@@
-                    {isPeanutWalletConnected && (!error || isInsufficientBalanceError) && (
+                    {(!error || isInsufficientBalanceError) && (
                         <Button
                             variant="purple"
                             loading={isProcessing}
                             shadowSize="4"
                             onClick={handleInitiatePayment}
                             disabled={isButtonDisabled}
                             className="w-full"
                             icon={getButtonIcon()}
                             iconSize={16}
                         >
                             {getButtonText()}
                         </Button>
                     )}
-                    {isPeanutWalletConnected && error && !isInsufficientBalanceError && (
+                    {error && !isInsufficientBalanceError && (
                         <Button
                             variant="purple"
                             loading={isProcessing}
                             shadowSize="4"
                             onClick={() => {
                                 handleInitiatePayment()
                             }}
                             disabled={isProcessing}
                             className="w-full"
                             icon="retry"
                             iconSize={16}
                         >
                             Retry
                         </Button>
                     )}

Also applies to: 754-769


271-301: Do not overwrite token input with a USD string

Here you compute USD from tokenAmount and then set inputTokenAmount to the USD value. That flips units from “token” to “USD,” which breaks later validations and conversions.

Apply this diff to only set the USD value:

@@
                 if (priceData) {
                     setRequestedTokenPrice(priceData.price)
 
                     if (requestDetails?.tokenAmount) {
                         // calculate USD value
                         const tokenAmount = parseFloat(requestDetails.tokenAmount)
-                        const usdValue = formatAmount(tokenAmount * priceData.price)
-                        setInputTokenAmount(usdValue)
-                        setUsdValue(usdValue)
+                        const usd = formatAmount(tokenAmount * priceData.price)
+                        setUsdValue(usd)
                     }
                 } else {

304-314: Parsing amounts without stripping thousands separators leads to wrong numbers

TokenAmountInput returns formatted decimals (e.g., "1,234.56"). Several places use parseFloat directly, which will parse only the leading “1” and treat the rest as invalid, causing false negatives, disabled CTAs, and wrong conversions.

Apply these diffs to consistently strip commas before numeric ops:

@@
-        } else if (isActivePeanutWallet) {
-            amountIsSet = !!inputTokenAmount && parseFloat(inputTokenAmount) > 0
+        } else if (isActivePeanutWallet) {
+            amountIsSet =
+                !!inputTokenAmount && parseFloat(String(inputTokenAmount).replace(/,/g, '')) > 0
         } else {
             amountIsSet =
-                (!!inputTokenAmount && parseFloat(inputTokenAmount) > 0) || (!!usdValue && parseFloat(usdValue) > 0)
+                (!!inputTokenAmount &&
+                    parseFloat(String(inputTokenAmount).replace(/,/g, '')) > 0) ||
+                (!!usdValue && parseFloat(String(usdValue).replace(/,/g, '')) > 0)
         }
@@
-        const numericAmount = parseFloat(inputTokenAmount)
+        const numericAmount = parseFloat(String(inputTokenAmount).replace(/,/g, ''))
         if (isNaN(numericAmount) || numericAmount <= 0) {
             if (!isExternalWalletFlow) return true
         }
@@
-        if (!inputTokenAmount || parseFloat(inputTokenAmount) <= 0) {
+        if (!inputTokenAmount || parseFloat(String(inputTokenAmount).replace(/,/g, '')) <= 0) {
             console.error('Invalid amount entered')
             dispatch(paymentActions.setError('Please enter a valid amount'))
             return
         }
@@
-        let tokenAmount = inputTokenAmount
+        let tokenAmount = inputTokenAmount
         if (
             requestedToken &&
             requestedTokenPrice &&
             (requestedChain !== selectedChainID || !areEvmAddressesEqual(requestedToken, selectedTokenAddress))
         ) {
-            tokenAmount = (parseFloat(inputUsdValue) / requestedTokenPrice).toString()
+            tokenAmount = (
+                parseFloat(String(inputUsdValue).replace(/,/g, '')) / requestedTokenPrice
+            ).toString()
         }
@@
-        if (isPintaReq && inputTokenAmount) {
-            dispatch(paymentActions.setBeerQuantity(Number(inputTokenAmount)))
+        if (isPintaReq && inputTokenAmount) {
+            dispatch(
+                paymentActions.setBeerQuantity(
+                    parseFloat(String(inputTokenAmount).replace(/,/g, '')) || 0
+                )
+            )
         }
@@
-        if (selectedTokenPrice) {
-            setUsdValue((parseFloat(inputTokenAmount) * selectedTokenPrice).toString())
+        if (selectedTokenPrice) {
+            const tokenAmt = parseFloat(String(inputTokenAmount).replace(/,/g, ''))
+            if (!isNaN(tokenAmt)) {
+                setUsdValue((tokenAmt * selectedTokenPrice).toString())
+            } else {
+                setUsdValue('')
+            }
         }

Also applies to: 561-565, 387-392, 414-421, 523-527, 529-534


271-301: Enforce client/server boundary for fetchTokenPrice

fetchTokenPrice is defined in a server-only module (src/app/actions/tokens.ts with "use server") and cannot be invoked directly from a client component. You’ll need to either:

  • Expose a client-safe API endpoint (e.g. /api/token-price) or
  • Lift this logic into a server component (using Suspense or server-side props) and pass the result down to PaymentForm.

Locations requiring updates:

  • src/components/Payment/PaymentForm/index.tsx, lines 271–301 (useEffect calling fetchTokenPrice)
  • src/components/Payment/PaymentForm/index.tsx, lines 387–421 (similar fetch usage)
  • src/app/actions/tokens.ts, lines 1 ("use server") & 106 (export of fetchTokenPrice)
♻️ Duplicate comments (1)
src/components/Payment/PaymentForm/index.tsx (1)

185-187: Thanks for keeping Daimo errors intact during balance checks

You stopped clearing Daimo errors in the balance-check effect. This prevents flicker and preserves actionable Daimo validation.

🧹 Nitpick comments (3)
src/components/Payment/PaymentForm/index.tsx (3)

770-781: Hide generic errors while Daimo completion is in-flight; also disable CTA when Daimo shows an error

Per team learnings, backend sync failures post-successful Daimo payments should not surface to users. Consume isDaimoPaymentProcessing from the store to hide generic errors during Daimo completion. Additionally, disable the CTA when daimoError is present.

Apply these diffs:

@@
-    const {
+    const {
         requestDetails,
         chargeDetails,
         beerQuantity,
-        daimoError,
+        daimoError,
+        isDaimoPaymentProcessing,
         error: paymentStoreError,
         attachmentOptions,
     } = usePaymentStore()
@@
-        if (isProcessing) return true
+        if (isProcessing) return true
+        if (isDaimoPaymentProcessing) return true
+        if (daimoError) return true
@@
-                    {!daimoError && error && (
+                    {!daimoError && !isDaimoPaymentProcessing && error && (
                         <ErrorAlert
                             description={
                                 (error ?? '').toLowerCase().includes('insufficient balance')
                                     ? 'Not enough balance to fulfill this request with Peanut'
                                     : error
                             }
                         />
                     )}

If preferred, we can instead gate the error source at the selector level and expose a canonical “userFacingError” that already respects Daimo state.

Also applies to: 80-86, 555-559


139-139: Remove unused isDepositRequest to avoid dead code

isDepositRequest is declared but never used; it’s also listed in handleInitiatePayment’s deps. Drop both to reduce noise.

Apply this diff:

@@
-    const isDepositRequest = searchParams.get('action') === 'deposit'
@@
-        isDepositRequest,

Also applies to: 454-471


551-553: Optional: move away from string-matching for business logic

Consider exposing a typed error code (e.g., 'INSUFFICIENT_BALANCE') from the store/initiator and computing isInsufficientBalanceError from that. This avoids brittle copy dependencies.

Happy to wire this through the payment-slice and initiator if you want.

📜 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 3726f83 and b249bc4.

📒 Files selected for processing (1)
  • src/components/Payment/PaymentForm/index.tsx (5 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-26T15:25:53.301Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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/Payment/PaymentForm/index.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/Payment/PaymentForm/index.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/Payment/PaymentForm/index.tsx
📚 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/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-22T07:25:59.258Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.258Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🧬 Code graph analysis (1)
src/components/Payment/PaymentForm/index.tsx (1)
src/hooks/usePaymentInitiator.ts (1)
  • usePaymentInitiator (80-831)
⏰ 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 (6)
src/components/Payment/PaymentForm/index.tsx (6)

179-183: Good: reset Daimo error on mount/recipient change only

Clearing Daimo errors on scope boundaries (component mount/recipient change) aligns with the learning to avoid showing backend-sync errors yet keep Daimo validations accurate.


693-696: Pushing live USD edits to Redux looks good

Forwarding USD edits via setUsdAmount keeps the store in sync with the UI. No concerns.


118-123: Minor: Error normalization is solid

Centralizing error normalization via ErrorHandler for both initiator and store errors is clean. LGTM.


473-521: CTA copy/icons are coherent

Dynamic label/icon selection covers connect/review/send/add-funds states. Once the insufficient balance matcher is fixed, this will behave as intended.


690-703: Amount input wiring is correct

Token amount and USD setters are plumbed correctly, and Peanut balance is hidden for external-wallet flows. Looks good.


706-725: Commented TokenSelector block

The note about Daimo handling token selection makes sense. Keep an eye on UX: if Daimo is not chosen, ensure token selection is available elsewhere.

If token selection is needed outside Daimo, confirm where that UI lives to avoid dead-ends.

Copy link

Review Daimo bugs

1 similar comment
Copy link

Review Daimo bugs

Copy link

Review Daimo bugs PR

Copy link
Contributor

@Hugo0 Hugo0 left a comment

Choose a reason for hiding this comment

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

approved preliminarily plus pls ping when youve answered Qs

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

🧹 Nitpick comments (3)
src/components/Common/ActionList.tsx (3)

38-64: Make ACTION_METHODS immutable and avoid accidental mutation.

If you decide to keep exporting ACTION_METHODS from this file, make it read-only to prevent runtime mutation (especially now that it becomes part of the public surface).

-export const ACTION_METHODS: Method[] = [
+export const ACTION_METHODS: ReadonlyArray<Method> = [
   {
     id: 'bank',
     title: 'Bank',
     description: 'EUR, USD, ARS (more coming soon)',
     icons: [
       'https://flagcdn.com/w160/ar.png',
       'https://flagcdn.com/w160/de.png',
       'https://flagcdn.com/w160/us.png',
     ],
     soon: false,
   },
   /* ... */
-]
+] as const

Note: If you adopt the “pass method as prop” approach (recommended in this review), you can also drop the export entirely to keep this purely an internal detail of ActionList.


98-98: Remove unnecessary async from handleMethodClick.

The function body has no await and returns synchronously. Dropping async avoids an implicit Promise return type and keeps intent clear.

-    const handleMethodClick = async (method: Method) => {
+    const handleMethodClick = (method: Method) => {

100-105: Sanitize USD parsing in request flow & clarify gating logic in claim flow

  • In the request branch (flow === 'request' at line 126):
    Current code

    const amountInUsd = usdAmount ? parseFloat(usdAmount) : 0
    if (method.id === 'bank' && amountInUsd < 1) {  }

    Issues:

    • A string containing only whitespace (e.g. ' ') is truthy, so parseFloat(' ')NaN.
    • NaN < 1 is false, so the “minimum $1” guard is silently bypassed.
    • Malformed inputs (letters, symbols) also yield NaN, leading to the same silent skip.
  • In the claim branch (flow === 'claim' at line 100):
    Current code

    const amountInUsd = parseFloat(formatUnits(claimLinkData.amount, claimLinkData.tokenDecimals))
    if (method.id === 'bank' && amountInUsd < 1) {  }

    Misnomer/mis-gating:

    • formatUnits(...) returns the raw token amount (e.g. 1.5 DAI), not its USD value.
    • If non-USD tokens (ETH, USDC, etc.) are ever used here, this check is gating on “token units” rather than “USD”.

Apply this diff in src/components/Common/ActionList.tsx (request branch):

- const amountInUsd = usdAmount ? parseFloat(usdAmount) : 0
+ // trim and parse, then guard against NaN
+ const parsedUsd = Number((usdAmount ?? '').trim())
+ const amountInUsd = Number.isFinite(parsedUsd) ? parsedUsd : 0

Follow-ups & next steps

  • Claim flow gating:

    • If you need a true USD threshold here, fetch the current token price (e.g. via an existing selector like usePrice(tokenAddress)) and compute
      const tokenAmount = Number(formatUnits(...))
      const amountInUsd = tokenAmount * currentTokenPrice
    • If this branch only ever sees USD-pegged tokens, rename
      // before
      const amountInUsd = parseFloat(formatUnits(...))
      // after
      const amountInToken = parseFloat(formatUnits(...))
      and update the threshold comment accordingly (e.g. “minimum 1 token”).
  • Centralize USD parsing:

    • Consider extracting a utility (e.g. parseUsdAmount(value: string|null): number) and using it in all components (ActionList, ActionListDaimoPayButton, transaction transformers, etc.) to ensure consistent behavior.

To verify all gating occurrences:

rg -n -C2 "const amountInUsd" src/components/Common/ActionList.tsx
📜 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 b249bc4 and fd31be6.

📒 Files selected for processing (3)
  • src/components/Common/ActionList.tsx (4 hunks)
  • src/components/Common/ActionListDaimoPayButton.tsx (1 hunks)
  • src/components/Payment/Views/Status.payment.view.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Common/ActionListDaimoPayButton.tsx
  • src/components/Payment/Views/Status.payment.view.tsx
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
📚 Learning: 2025-08-26T15:25:53.301Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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/ActionList.tsx
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/ActionList.tsx
📚 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/components/Common/ActionList.tsx
⏰ 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

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: 1

Caution

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

⚠️ Outside diff range comments (1)
src/components/Common/ActionList.tsx (1)

28-34: Remove the local Method interface here; import the type from the constants module to break the cycle.

Defining Method here while the constants file imports it reintroduces a circular dependency. Move the type alongside the constants (or a shared types module) and import it here as a type.

Apply this diff to delete the local interface:

-export interface Method {
-    id: string
-    title: string
-    description: string
-    icons: any[]
-    soon: boolean
-}

Then add this import alongside other imports (outside the selected range):

import type { Method } from '@/constants/actionlist.consts'

Optional tightening (if you control the type): define MethodId = 'bank' | 'mercadopago' | 'exchange-or-wallet' and use it for id; narrow icons to a readonly union rather than any[].

♻️ Duplicate comments (2)
src/components/Common/ActionList.tsx (2)

25-26: Code-split the Daimo button and avoid SSR/window issues; also helps decouple dependencies.

Importing ActionListDaimoPayButton directly can cause SSR headaches if it touches window, and worsens coupling. Use a dynamic import with ssr: false. This aligns with earlier guidance in this PR thread.

-import ActionListDaimoPayButton from './ActionListDaimoPayButton'
 import { ACTION_METHODS } from '@/constants/actionlist.consts'

Add this import near the top (outside the selected range):

import dynamic from 'next/dynamic'
const ActionListDaimoPayButton = dynamic(() => import('./ActionListDaimoPayButton'), { ssr: false })

Quick check for any window usage in the Daimo button:

#!/bin/bash
rg -n "ActionListDaimoPayButton\.tsx" -C2
rg -n "\bwindow\b" src/components/Common/ActionListDaimoPayButton.tsx -C2 || true

153-156: Pass the method into the Daimo button to avoid cross-module lookups and hidden cycles.

Render-prop the resolved method so ActionListDaimoPayButton doesn’t import ACTION_METHODS (or ActionList) internally. This also improves testability.

-                {ACTION_METHODS.map((method) => {
-                    if (flow === 'request' && method.id === 'exchange-or-wallet') {
-                        return <ActionListDaimoPayButton key={method.id} />
-                    }
+                {ACTION_METHODS.map((method) => {
+                    if (flow === 'request' && method.id === 'exchange-or-wallet') {
+                        return <ActionListDaimoPayButton key={method.id} method={method} />
+                    }

And in src/components/Common/ActionListDaimoPayButton.tsx, accept the prop and remove any imports of ACTION_METHODS:

// at top
import type { Method } from '@/constants/actionlist.consts'

type Props = { method: Method }
export default function ActionListDaimoPayButton({ method }: Props) {
  // ...
}

Confirm the button no longer imports ACTION_METHODS and does not show user-facing errors on backend sync failures (per retrieved learnings):

#!/bin/bash
# No direct ACTION_METHODS import
rg -n "import .*ACTION_METHODS" src/components/Common/ActionListDaimoPayButton.tsx || true

# Assert no user-facing error surfaces for post-success sync (toast/alert)
rg -nP "toast|alert|ActionModal|console\.(error|warn)" src/components/Common/ActionListDaimoPayButton.tsx -C2 || true
🧹 Nitpick comments (2)
src/constants/actionlist.consts.ts (1)

6-32: Make ACTION_METHODS immutable and tighten typing.

Exposing it as a mutable Method[] invites unintended mutation. Prefer a readonly literal with satisfies for compile-time checks.

-export const ACTION_METHODS: Method[] = [
+export const ACTION_METHODS = [
     {
         id: 'bank',
         title: 'Bank',
         description: 'EUR, USD, ARS (more coming soon)',
         icons: [
             'https://flagcdn.com/w160/ar.png',
             'https://flagcdn.com/w160/de.png',
             'https://flagcdn.com/w160/us.png',
         ],
         soon: false,
     },
     {
         id: 'mercadopago',
         title: 'Mercado Pago',
         description: 'Instant transfers',
         icons: [MERCADO_PAGO_ICON],
         soon: true,
     },
     {
         id: 'exchange-or-wallet',
         title: 'Exchange or Wallet',
         description: 'Binance, Coinbase, Metamask and more',
         icons: [binanceIcon, TRUST_WALLET_SMALL_LOGO, METAMASK_LOGO],
         soon: false,
     },
-]
+] as const satisfies ReadonlyArray<Method>

Optional: If you keep the Method type here, consider refining icons to a safer union (e.g., ReadonlyArray<string | StaticImport> if using next/image).

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

96-96: Make amount parsing resilient to non-numeric strings.

Current check treats any non-empty string as parseable; whitespace like ' ' yields NaN. Use a numeric guard.

-            const amountInUsd = usdAmount ? parseFloat(usdAmount) : 0
+            const amountInUsd = Number.isFinite(Number(usdAmount)) ? Number(usdAmount) : 0
📜 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 fd31be6 and 1333ae2.

📒 Files selected for processing (3)
  • src/components/Common/ActionList.tsx (3 hunks)
  • src/components/Common/ActionListDaimoPayButton.tsx (1 hunks)
  • src/constants/actionlist.consts.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Common/ActionListDaimoPayButton.tsx
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
📚 Learning: 2025-08-26T17:38:37.017Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/components/Common/ActionList.tsx:153-156
Timestamp: 2025-08-26T17:38:37.017Z
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: 2025-08-26T15:25:53.301Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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/ActionList.tsx
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/ActionList.tsx
📚 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/components/Common/ActionList.tsx
🧬 Code graph analysis (2)
src/constants/actionlist.consts.ts (1)
src/components/Common/ActionList.tsx (1)
  • Method (28-34)
src/components/Common/ActionList.tsx (1)
src/constants/actionlist.consts.ts (1)
  • ACTION_METHODS (6-32)
⏰ 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). (2)
  • GitHub Check: Deploy-Preview
  • GitHub Check: test
🔇 Additional comments (1)
src/constants/actionlist.consts.ts (1)

11-15: No action needed: wildcard remotePatterns already covers flagcdn.com

The next.config.js file defines images.remotePatterns with a wildcard hostname for both HTTP and HTTPS, which includes flagcdn.com. Therefore, external images from https://flagcdn.com/... will load successfully with Next.js’s <Image> component.

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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/components/Common/ActionList.tsx (1)

60-67: Ensure correct USD conversion in claim flow before enforcing the $1 minimum

The amountInUsd computed in handleMethodClick is actually the raw token amount—not USD—because it’s derived solely via formatUnits(claimLinkData.amount, claimLinkData.tokenDecimals) (which returns token units). If claimLinkData.tokenSymbol ever represents a non‐USD‐pegged token (e.g. ETH or other ERC-20), the bank-payout guard (if (method.id === 'bank' && amountInUsd < 1)) will erroneously block legitimate payouts or allow sub-$1 cashouts. To fix:

• In src/components/Common/ActionList.tsx around lines 61–65:
– Rename the raw token amount to something like amountInToken.
– Fetch or inject the current USD price (e.g. via an existing useTokenPrice hook or context) and compute
ts const amountInToken = parseFloat(formatUnits(claimLinkData.amount, claimLinkData.tokenDecimals)) const amountInUsd = amountInToken * (tokenPrice ?? 0)
– Then enforce the $1 minimum on amountInUsd.

• If your UI restricts send links to USD‐pegged tokens only, rename the variable to amountInToken to avoid confusion and document that restriction; otherwise, integrate a price feed before applying the threshold.

Mandatory fix

♻️ Duplicate comments (2)
src/components/Common/ActionList.tsx (2)

25-26: Code-split Daimo button and disable SSR to avoid hydration/TDZ issues

The Daimo button is likely browser-only (payment SDKs often touch window). Code-splitting and disabling SSR reduce initial bundle and avoid SSR pitfalls. This also aligns with earlier guidance.

-import ActionListDaimoPayButton from './ActionListDaimoPayButton'
+import dynamic from 'next/dynamic'
+const ActionListDaimoPayButton = dynamic(() => import('./ActionListDaimoPayButton'), { ssr: false })
 import { ACTION_METHODS, PaymentMethod } from '@/constants/actionlist.consts'

145-148: Pass the method into the Daimo button for better isolation and testability

Even though the constants are centralized, passing the current method avoids hidden cross-module lookups and keeps the button self-contained.

-                {ACTION_METHODS.map((method) => {
-                    if (flow === 'request' && method.id === 'exchange-or-wallet') {
-                        return <ActionListDaimoPayButton key={method.id} />
-                    }
+                {ACTION_METHODS.map((method) => {
+                    if (flow === 'request' && method.id === 'exchange-or-wallet') {
+                        return <ActionListDaimoPayButton key={method.id} method={method} />
+                    }

And update ActionListDaimoPayButton.tsx to accept method: PaymentMethod.

🧹 Nitpick comments (6)
src/components/Request/views/ExternalWalletFulfilMethods.tsx (2)

3-3: Avoid importing MethodCard from a heavy module; extract to a lightweight component

Importing MethodCard from ActionList.tsx can pull in that entire module’s client-side code and its dependencies. Consider extracting MethodCard into its own file (e.g., src/components/Common/MethodCard.tsx) so both ActionList and this view can import a minimal component.

I can generate the extraction patch if you want.


36-41: Docstring typo: “fullfilling” → “fulfilling”

Minor spelling fix for clarity and searchability.

- * Shows a list of available payment methods to choose from for claiming a send link or fullfilling a request link
+ * Shows a list of available payment methods to choose from for claiming a send link or fulfilling a request link
src/components/Common/ActionList.tsx (1)

36-41: Docstring typo: “fullfilling” → “fulfilling”

Minor spelling fix.

- * Shows a list of available payment methods to choose from for claiming a send link or fullfilling a request link
+ * Shows a list of available payment methods to choose from for claiming a send link or fulfilling a request link
src/constants/actionlist.consts.ts (3)

5-11: Strengthen types: make icons immutable to prevent accidental mutation

Use a readonly array for icons to better reflect constant data and help TS catch unintended writes.

 export interface PaymentMethod {
-    id: string
+    id: string
     title: string
     description: string
-    icons: any[]
+    icons: ReadonlyArray<any>
     soon: boolean
 }

Optionally, define a dedicated IconSource type matching IconStack’s expectations if available.


13-39: Freeze ACTION_METHODS and keep it strictly typed

Mark the array as readonly and validate shape with satisfies. This improves type safety, preserves literal ids, and avoids accidental mutation.

-export const ACTION_METHODS: PaymentMethod[] = [
+export const ACTION_METHODS = [
   {
     id: 'bank',
     title: 'Bank',
     description: 'EUR, USD, ARS (more coming soon)',
     icons: [
       'https://flagcdn.com/w160/ar.png',
       'https://flagcdn.com/w160/de.png',
       'https://flagcdn.com/w160/us.png',
     ],
     soon: false,
   },
   {
     id: 'mercadopago',
     title: 'Mercado Pago',
     description: 'Instant transfers',
     icons: [MERCADO_PAGO_ICON],
     soon: true,
   },
   {
     id: 'exchange-or-wallet',
     title: 'Exchange or Wallet',
     description: 'Binance, Coinbase, Metamask and more',
     icons: [binanceIcon, TRUST_WALLET_SMALL_LOGO, METAMASK_LOGO],
     soon: false,
   },
-]
+] as const satisfies ReadonlyArray<PaymentMethod>

5-6: Optional: Centralize method ids as a union to remove magic strings across the app

Defining a PaymentMethodId union helps prevent typos in switches and lookups.

 export interface PaymentMethod {
-    id: string
+    id: PaymentMethodId
     title: string
     description: string
     icons: ReadonlyArray<any>
     soon: boolean
 }
+
+export type PaymentMethodId = 'bank' | 'mercadopago' | 'exchange-or-wallet'

Note: adopting this will require small updates where id is referenced.

📜 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 1333ae2 and 68ad69d.

📒 Files selected for processing (3)
  • src/components/Common/ActionList.tsx (5 hunks)
  • src/components/Request/views/ExternalWalletFulfilMethods.tsx (1 hunks)
  • src/constants/actionlist.consts.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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.
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.

Applied to files:

  • src/components/Request/views/ExternalWalletFulfilMethods.tsx
📚 Learning: 2025-08-26T17:38:37.017Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/components/Common/ActionList.tsx:153-156
Timestamp: 2025-08-26T17:38:37.017Z
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/components/Request/views/ExternalWalletFulfilMethods.tsx
  • src/constants/actionlist.consts.ts
  • src/components/Common/ActionList.tsx
📚 Learning: 2025-08-26T15:25:53.301Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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/ActionList.tsx
📚 Learning: 2025-08-22T07:28:32.260Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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/ActionList.tsx
📚 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/components/Common/ActionList.tsx
🧬 Code graph analysis (2)
src/components/Request/views/ExternalWalletFulfilMethods.tsx (1)
src/constants/actionlist.consts.ts (1)
  • PaymentMethod (5-11)
src/components/Common/ActionList.tsx (1)
src/constants/actionlist.consts.ts (2)
  • PaymentMethod (5-11)
  • ACTION_METHODS (13-39)
⏰ 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 (2)
src/components/Common/ActionList.tsx (1)

186-186: Type alignment looks good

Switching MethodCard’s prop to PaymentMethod aligns with the centralized type. No issues.

src/constants/actionlist.consts.ts (1)

1-39: Overall: Good centralization of action methods and types

Moving the shared type and constants here eliminates prior cycles and improves reuse. The structure is clear and extensible.

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: 1

Caution

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

⚠️ Outside diff range comments (2)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (2)

206-207: Bug: fee can be a string; as number doesn’t coerce at runtime.

If transaction.fee is a string (per type), formatAmount receives a string and may mis-render. Normalize first.

-const feeDisplay = transaction.fee !== undefined ? formatAmount(transaction.fee as number) : 'N/A'
+const feeNumeric =
+    transaction.fee !== undefined
+        ? (typeof transaction.fee === 'string' ? Number(transaction.fee) : transaction.fee)
+        : undefined
+const feeDisplay = feeNumeric !== undefined && Number.isFinite(feeNumeric) ? formatAmount(feeNumeric as number) : 'N/A'

731-755: Gate the “Cancel link” button on the presence of setShowCancelLinkModal.

Without this guard (and with the previous noop default removed), the button could still render and do nothing. Add the setter to the condition.

-                    {(transaction.extraDataForDrawer.originalType === EHistoryEntryType.SEND_LINK ||
-                        transaction.extraDataForDrawer.originalType === EHistoryEntryType.REQUEST) &&
-                        transaction.extraDataForDrawer.originalUserRole === EHistoryUserRole.SENDER &&
-                        setIsLoading &&
-                        onClose && (
+                    {(transaction.extraDataForDrawer.originalType === EHistoryEntryType.SEND_LINK ||
+                        transaction.extraDataForDrawer.originalType === EHistoryEntryType.REQUEST) &&
+                        transaction.extraDataForDrawer.originalUserRole === EHistoryUserRole.SENDER &&
+                        setIsLoading &&
+                        onClose &&
+                        setShowCancelLinkModal && (

Optional: with the guard in place, you can drop ?. from setShowCancelLinkModal?.(true).

🧹 Nitpick comments (6)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (6)

17-17: Prefer type-only imports (and avoid default React import if unused at runtime).

Use type-only imports for Dispatch/SetStateAction to keep them erased at compile time. If you don’t rely on React as a value (new JSX transform), you can also drop the default import; otherwise keep it. Minimal change:

-import React, { Dispatch, SetStateAction, useMemo, useState } from 'react'
+import React, { useMemo, useState, type Dispatch, type SetStateAction } from 'react'

40-50: Unify setter types: use Dispatch<SetStateAction> for setIsLoading.

setIsLoading is a state setter semantically; type it the same as setShowCancelLinkModal for accuracy and consistency.

 interface TransactionDetailsReceiptProps {
   transaction: TransactionDetails | null
   onClose?: () => void
   isLoading?: boolean
-  setIsLoading?: (isLoading: boolean) => void
+  setIsLoading?: Dispatch<SetStateAction<boolean>>
   contentRef?: React.RefObject<HTMLDivElement>
   transactionAmount?: string // dollarized amount of the transaction
   showCancelLinkModal?: boolean
   setShowCancelLinkModal?: Dispatch<SetStateAction<boolean>>
   className?: string
 }

191-204: Handle bigint safely when formatting amounts.

transaction.amount can be number | bigint. Asserting with as number won’t convert at runtime; use Number() to handle bigint consistently.

-            amountDisplay = `$ ${formatAmount(transaction.amount as number)}`
+            amountDisplay = `$ ${formatAmount(Number(transaction.amount))}`
...
-            amountDisplay = `$ ${formatAmount(transaction.amount as number)}`
+            amountDisplay = `$ ${formatAmount(Number(transaction.amount))}`

296-305: Normalize cancelledDate to Date before formatting (consistency with other date fields).

cancelledDate is string | Date. Unlike other places, here it’s not wrapped in new Date(...). Align for robustness:

-    <PaymentInfoRow
-        label="Cancelled"
-        value={formatDate(transaction.cancelledDate as Date)}
-    />
+    <PaymentInfoRow
+        label="Cancelled"
+        value={formatDate(new Date(transaction.cancelledDate as any))}
+    />

908-913: Avoid non-null assertion on bridgeTransferId; guard and surface actionable error.

transaction.extraDataForDrawer?.bridgeTransferId! risks runtime errors if undefined. Guard and bail early, or disable the button when not present.

-// first cancel the onramp
-await cancelOnramp(transaction.extraDataForDrawer?.bridgeTransferId!)
+// first cancel the onramp
+const transferId = transaction.extraDataForDrawer?.bridgeTransferId
+if (!transferId) {
+  captureException(new Error('Missing bridgeTransferId while canceling bank request'))
+  setIsLoading(false)
+  return
+}
+await cancelOnramp(transferId)

951-982: Optional: Normalize CancelSendLinkModal prop name to camelCase

We verified that in src/components/Global/CancelSendLinkModal/index.tsx the interface and destructured prop are currently defined as:

interface CancelSendLinkModalProps {
    showCancelLinkModal: boolean
    setshowCancelLinkModal: (show: boolean) => void
    
}
const CancelSendLinkModal = ({
    showCancelLinkModal,
    setshowCancelLinkModal,}) => {  }

All call sites (e.g. in TransactionDetailsReceipt.tsx and Success.link.send.view.tsx) correctly pass setshowCancelLinkModal. However, this deviates from the standard camelCase convention (which would be setShowCancelLinkModal) and can hinder editor auto-complete and readability.

If you’d like to align with React naming conventions, consider renaming the prop across the board:

Modal definition (src/components/Global/CancelSendLinkModal/index.tsx)

 interface CancelSendLinkModalProps {
-   setshowCancelLinkModal: (show: boolean) => void
+   setShowCancelLinkModal: (show: boolean) => void
 }

 const CancelSendLinkModal = ({
-   setshowCancelLinkModal,
+   setShowCancelLinkModal,
   …
 }) => { … }

Call sites

  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx
  • src/components/Send/link/views/Success.link.send.view.tsx
-    <CancelSendLinkModal
-       showCancelLinkModal={…}
-       setshowCancelLinkModal={setShowCancelLinkModal}
+    <CancelSendLinkModal
+       showCancelLinkModal={…}
+       setShowCancelLinkModal={setShowCancelLinkModal}
        …
    />

If you’d rather preserve the existing API for now, this change isn’t strictly required—feel free to ignore this suggestion.

📜 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 68ad69d and 975396b.

📒 Files selected for processing (1)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:522-545
Timestamp: 2025-08-22T07:28:32.260Z
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.
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.301Z
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.
🧬 Code graph analysis (1)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)
src/components/TransactionDetails/transactionTransformer.ts (1)
  • TransactionDetails (40-120)
🔇 Additional comments (1)
src/components/TransactionDetails/TransactionDetailsReceipt.tsx (1)

419-675: Deposit instructions: great UX touches.

The expandable bank details, copy-to-clipboard affordances, and contextual MoreInfo tooltip are cohesive and well-structured. Nice work on the conditional EU/US layouts.

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 (3)
src/components/Payment/PaymentForm/index.tsx (3)

547-549: Fix mismatch in insufficient-balance detection (prevents Add Funds CTA and wrong alert mapping).

Balance-check sets errors like 'Insufficient balance' or 'Insufficient balance in connected wallet', but the UI checks for "You don't have enough balance." Use a consistent predicate.

@@
-    const isInsufficientBalanceError = useMemo(() => {
-        return error?.includes("You don't have enough balance.")
-    }, [error])
+    const isInsufficientBalanceError = useMemo(() => {
+        return !!error && (/\binsufficient balance\b/i.test(error) || error.includes("You don't have enough balance."))
+    }, [error])
@@
-                    {!daimoError && error && (
-                        <ErrorAlert
-                            description={
-                                error.includes("You don't have enough balance.")
-                                    ? 'Not enough balance to fulfill this request with Peanut'
-                                    : error
-                            }
-                        />
-                    )}
+                    {!daimoError && error && (
+                        <ErrorAlert
+                            description={
+                                isInsufficientBalanceError
+                                    ? 'Not enough balance to fulfill this request with Peanut'
+                                    : error
+                            }
+                        />
+                    )}

Also applies to: 763-771


300-309: Parse user-entered numbers safely (commas cause wrong amounts and NaN propagation).

TokenAmountInput returns formatted decimals (e.g., "1,234.56"). Use a helper to strip commas before numeric ops to avoid undercounting (parseFloat('1,000') => 1) and NaN.

Add once (anywhere inside component scope, e.g., after state hooks):

const parseDecimal = (v: string | number | undefined | null) =>
  Number(String(v ?? '').replace(/,/g, ''));

Apply diffs:

@@
-        } else if (isActivePeanutWallet) {
-            amountIsSet = !!inputTokenAmount && parseFloat(inputTokenAmount) > 0
+        } else if (isActivePeanutWallet) {
+            amountIsSet = !!inputTokenAmount && parseDecimal(inputTokenAmount) > 0
@@
-            amountIsSet =
-                (!!inputTokenAmount && parseFloat(inputTokenAmount) > 0) || (!!usdValue && parseFloat(usdValue) > 0)
+            amountIsSet =
+                (!!inputTokenAmount && parseDecimal(inputTokenAmount) > 0) || (!!usdValue && parseDecimal(usdValue) > 0)
@@
-        if (!inputTokenAmount || parseFloat(inputTokenAmount) <= 0) {
+        if (!inputTokenAmount || parseDecimal(inputTokenAmount) <= 0) {
             console.error('Invalid amount entered')
             dispatch(paymentActions.setError('Please enter a valid amount'))
             return
         }
@@
-            tokenAmount = (parseFloat(inputUsdValue) / requestedTokenPrice).toString()
+            tokenAmount = (parseDecimal(inputUsdValue || usdValue) / requestedTokenPrice).toString()
@@
-        if (isPintaReq && inputTokenAmount) {
-            dispatch(paymentActions.setBeerQuantity(Number(inputTokenAmount)))
+        if (isPintaReq && inputTokenAmount) {
+            dispatch(paymentActions.setBeerQuantity(parseDecimal(inputTokenAmount)))
@@
-        if (selectedTokenPrice) {
-            setUsdValue((parseFloat(inputTokenAmount) * selectedTokenPrice).toString())
+        if (selectedTokenPrice) {
+            setUsdValue((parseDecimal(inputTokenAmount) * selectedTokenPrice).toString())
@@
-        if (isPintaReq) {
-            dispatch(paymentActions.setBeerQuantity(Number(inputTokenAmount)))
+        if (isPintaReq) {
+            dispatch(paymentActions.setBeerQuantity(parseDecimal(inputTokenAmount)))
@@
-        const numericAmount = parseFloat(inputTokenAmount)
-        if (isNaN(numericAmount) || numericAmount <= 0) {
+        const numericAmount = parseDecimal(inputTokenAmount)
+        if (!Number.isFinite(numericAmount) || numericAmount <= 0) {
@@
-            return (
-                !inputTokenAmount ||
-                isNaN(parseFloat(inputTokenAmount)) ||
-                parseFloat(inputTokenAmount) <= 0 ||
+            return (
+                !inputTokenAmount ||
+                !Number.isFinite(parseDecimal(inputTokenAmount)) ||
+                parseDecimal(inputTokenAmount) <= 0 ||
                 !selectedTokenAddress ||
                 !selectedChainID ||
                 isProcessing
             )

Also add usdValue to handleInitiatePayment deps (since we used it for conversion):

@@
-        requestedTokenPrice,
+        requestedTokenPrice,
+        usdValue,

Also applies to: 383-388, 416-417, 520-523, 525-530, 540-545, 556-571


280-286: Don’t overwrite token amount with USD; only set the USD field.

This flips the token input to show USD text, likely confusing users and breaking validation that expects token units.

-                        const usdValue = formatAmount(tokenAmount * priceData.price)
-                        setInputTokenAmount(usdValue)
-                        setUsdValue(usdValue)
+                        const usdValue = formatAmount(tokenAmount * priceData.price)
+                        setUsdValue(usdValue)
♻️ Duplicate comments (1)
src/components/Payment/PaymentForm/index.tsx (1)

175-183: Resolved: Daimo errors are no longer cleared in the balance-check effect.

Clearing daimoError only on mount/recipient change matches prior guidance; prevents flicker.

🧹 Nitpick comments (1)
src/components/Payment/PaymentForm/index.tsx (1)

135-136: Remove unused isDepositRequest (and its dependency).

It’s defined but not used; transactionType derives from isExternalWalletFlow.

-    const isDepositRequest = searchParams.get('action') === 'deposit'
@@
-        isDepositRequest,
         isConnected,

Also applies to: 449-468

📜 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 99056f0 and c649132.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/app/[...recipient]/client.tsx (2 hunks)
  • src/components/Payment/PaymentForm/index.tsx (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/[...recipient]/client.tsx
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
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.
📚 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/Payment/PaymentForm/index.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/Payment/PaymentForm/index.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/Payment/PaymentForm/index.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.

Applied to files:

  • src/components/Payment/PaymentForm/index.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/Payment/PaymentForm/index.tsx
📚 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/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Global/TokenAmountInput/index.tsx:23-30
Timestamp: 2024-10-29T12:19:41.968Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), when the 'Max' button is clicked, we intentionally set the input denomination to 'TOKEN' because we are setting the value as token.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/Link/Input.view.tsx:244-248
Timestamp: 2024-10-29T12:20:47.207Z
Learning: In the `TokenAmountInput` component within `src/components/Global/TokenAmountInput/index.tsx`, when `balance` is undefined, the `maxValue` prop should be set to an empty string `''`.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1104
File: src/components/Payment/PaymentForm/index.tsx:596-600
Timestamp: 2025-08-22T07:25:59.304Z
Learning: The `TokenAmountInput` component in `src/components/Global/TokenAmountInput/` always returns decimal strings (e.g., "1,234.56"), not base units. When passing these values to external APIs like Daimo's `toUnits` prop, simply stripping commas with `.replace(/,/g, '')` is sufficient.

Applied to files:

  • src/components/Payment/PaymentForm/index.tsx
🧬 Code graph analysis (1)
src/components/Payment/PaymentForm/index.tsx (1)
src/hooks/usePaymentInitiator.ts (1)
  • usePaymentInitiator (80-831)
⏰ 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). (2)
  • GitHub Check: Deploy-Preview
  • GitHub Check: test
🔇 Additional comments (1)
src/components/Payment/PaymentForm/index.tsx (1)

684-687: Good: propagate USD value to the store alongside local state.

Keeps Redux in sync with the input component without extra effects.

@Zishan-7 Zishan-7 merged commit 6d71e01 into peanut-wallet-dev Aug 27, 2025
6 of 7 checks passed
jjramirezn added a commit that referenced this pull request Sep 4, 2025
* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <[email protected]>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* Prod to staging (#1124)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <[email protected]>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <[email protected]>
Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

---------

Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Kushagra Sarathe <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

* fix: dates in receipts (#1105)

* [TASK-13865] fix: add tx info on receipt (#1109)

* fix: add tx info on receipt

* feat: use address explorer url for depositor address

* fix(history): check befroe creating address explorer url

* Fix: logged in users have to re-login after installing PWA (#1103)

* store `LOCAL_STORAGE_WEB_AUTHN_KEY` in cookies

* ensure backward compatibility

* refactor: move syncLocalStorageToCookie call into useEffect for better lifecycle management

* feat: links v2.1 req fulfilment flows (#1085)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* feat: req fulfillment exchange flow

* fix: header title

* feat: req fulfillment using connected external wallet

* fix: navigation and ui

* fix: file name

* feat: abstract reusbale components from onramp flow for bank fulfilment

* feat: handle onramp creation for request fulfilment

* feat: reusable verification component

* feat: handle bank req fulfilment for peanut users

* fix: show all supported countries in req/claim bank flow

* feat: show google-pay/apple-pay based on users device

* fix: resolve pr review comments

* fix: exhange rate hook fallback value

* fix: resolve pr comments

* Feat: Collect tg username (#1110)

* feat: collect tg username

* update animations

* fix api route

* add thinking peanut gif

* fix typescript errors

* fix typo and reset telegramHandle field on logout

* fix: spacing and describe regex rules

* add missing export

* feat: add sound in success views (#1127)

* feat: handle history ui changes for links v2.1 (#1106)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* feat: req fulfillment exchange flow

* fix: header title

* feat: req fulfillment using connected external wallet

* fix: navigation and ui

* fix: file name

* feat: abstract reusbale components from onramp flow for bank fulfilment

* feat: handle onramp creation for request fulfilment

* feat: reusable verification component

* feat: handle bank req fulfilment for peanut users

* fix: show all supported countries in req/claim bank flow

* feat: show google-pay/apple-pay based on users device

* feat: handle bank send link claim hisotry for peanut users

* feat: handle history ui changes for request fulfillment using bank accounts

* fix: resolve pr review comments

* fix: exhange rate hook fallback value

* fix: resolve pr comments

* fix: review comments

* feat: badges updates (#1119)

* feat: badges updates and hook to check for interactions

* feat: handle badges for receipts and drawer header

* feat: handle badges on request and send flow

* feat: tooltip for badges

* fix: tooltip positioning

* fix: associate a external wallet claim to user if logged in (#1126)

* fix: associate a external wallet claim to user if logged in

* chore: fix comments

* [TASK-14113] fix: handle rpc outage when creating sendlinks (#1120)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* fix: handle rpc outage when creating sendlinks

* fix: formatting

* fix: parallelize geting deposit index

---------

Co-authored-by: Mohd Zishan <[email protected]>

* Integrate Daimo Pay (#1104)

* add daimo pay

* minor improvements

* cleanup and add success state

* resolve dependency issues

* fix: formatting

* fix: recent methods redirection

* add functions for daimo payment in request fulfilment flow

* Integrate daimo in request fulfilment flow

* remove hardcoded address

* add separate arbitrum usdc flow for deposits

* Add risk modal

* fix overlay blur

* Enhance loading state indication in payment process

* Add payer's address in deposit history entry

* Add validation

* add error handling

* remove action and move logic to API route

* fix errors

* fix: request flow

* fix: validation

* fixes

* add daimo flow in country specific method

* fix: slider not working on first attempt

* filter supported networks

* create reusable daimo button

* remove space

* remove route.ts file and move logic to server actions

* fix: infinite loading edge case

* update api and remove delay

* fix: layout shift

* fix: shadow

* update function name

* fix: success receipt (#1129)

* fix: roboto font not working (#1130)

* fix: allow cancel link from the claim page

* fix: allow canceling links from the shared receipt (#1134)

* fix: send flow cta (#1133)

* fix: send flow ctas

* fix: success sound on send flow

* fix: disabled btn on req pay flow

* Fix Daimo bugs (#1132)

* fix: bugs

* fix cross chain deposit details not correct

* fix: request screen UI

* add loading state

* remove old daimo button

* fix: missing dependencies and dead code

* add try catch finally block

* remove clear Daimo errors inside the balance-check effect

* fix copy

* minor fixes

* move ACTION_METHODS to constants file to remove circular dependency

* fix: circular dependency

* fix ts error

* update daimo version

* [TASK-14095] feat: add fallback transport to viem clients (#1131)

* feat: add fallback transport to viem clients

Use viem fallback transport to handle RPC errors and fallback to other
providers.

* style: Apply prettier formatting

* test: add fallback to viem mock

* fix: external claim links history ui + badges fix (#1136)

* fix: external claim links history ui + badges fix

* fix: resolve codderrabbit suggestions

* fix: coderrabbit comment on state stale

* Fix: disable add money button on default state + disable sound on IOS (#1145)

* fix: add money success screen shows usernmae

* disable add money button in default state

* disable sound on IOS

* Fix: daimo bugs part2 (#1149)

* fix: black screen on IOS

* fix: sucess screen showed without paying - add money flow

* fix currency and double $ in  txn history

* fix: x-chan token size and add API to get missing token icons

* fix: req fulfilment

* add default value to tokenData

* fix: move useeffect above transaction null check

* format amount

* fix: space between currency and amount (#1135)

* Lock token to USDC arb for peanut ens username (#1128)

* Lock token to USDC arb for peanut ens username

* add comment

* revert variable declaration for sanitizedValue in GeneralRecipientInput component

* fix add regex to strip only from the end

* [TASK-13900] Feat/kyc modal changes (#1137)

* fix: pointer events

* fix: modal btns not working on mobile

* add missing dependency

* remove close button

* Chore/prod to dev 106 (#1152)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <[email protected]>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <[email protected]>
Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

* fix: bank claim flow runtime error (#1138)

* hotfix: make iban non optional (#1139)

* fix: bank claim flow runtime error

* fix: dont have iban as optional

* fix: merge conflicts

* fix: merge external account with bank details (#1140)

* fix: add id to external account (#1142)

* added tg footer (#1144)

* Hotfix : add missing countries - claim as guest flow (#1146)

* fix: add missing countries

* remove duplicate comment

* fix: show error on dynamic bank account form (#1147)

* fix: Invalid IBAN for UK (#1151)

---------

Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Kushagra Sarathe <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

* [TASK-13950] Fix: incorrect token amount on second withdraw (#1150)

* fix: incorrect token amount on second withdraw

* move `resetTokenContextProvider()` to unmount callback

* fix: transaction explorer url for deposits

* fix: history skeleton copy

* save token and chain details for cross chain req-fulfilments (#1154)

* fix: send links history ui for senders pov when claimed to bank accounts (#1156)

* fix: sort action list methods

* fix: send links claimed to bank accounts history ui for senders pov

* fix: issues for request link paying with bank (#1158)

- Specify recipient when creating onramp for request fulfillment
- Use correct amount depending on currency

* fix: stop cleaning error by bic field (#1159)

We now always clear before starting submission and also bic field will
always show, so that logic is not needed anymore.

* fix: claim country currency and amount, fallback to $  (#1164)

* feat: show local bank currency incase of bank claims

* fix: activity rows for sender's send link history

* fix: verification modal when claiming

* fix: state issue when new user tries to claim to bank

* fix: request pay copy (#1165)

* fix: close kyc modal btn (#1166)

* Fix testing github action (#1167)

* chore: remove prettier action

When commiting it clashes with signature verification rules

* chore: update test action setup version

* fix: install first

* fix: actually make sure that cancelledDate is a Date (#1170)

* fix: icon and margin (#1171)

* Hide pay with wallet button in Daimo component (#1172)

* hide pay with wallet button

* improve targeted css approach

* Fix: Daimo bug and activity receipt bug (#1175)

* sligify chain name

* fix: stale state issue

* hide row if tokenData is not present

* Fix/conflicts (#1177)

* HOTFIX - IBAN country detection and incorrect bank acc details (#1094)

* Fix: Iban country detection and incorrect bank acc details

* Fix: update IBAN country validation to use correct locale string comparison

* add validations for US and mexican bank accounts

* fix typo

* fix claim flow and create a reusable function for getting 3 letter code

* fix country code mismatch

* fix: show error below input field

* remove unnecessary checks

* remove unnecessary CLABE check

* Prod LP v2.1 (#1098)

* feat: lpv2.1

* fix: gigaclouds, font and exchange widget

* fixes and improvements

* remove duplicate export

* remove unused component

* Fix: Landing page hero section responsiveness issue (#1107)

* fix: hero section responsiveness issue

* fix: stars position

* fix height on desktop

* remove unused code

* fix margins (#1113)

* [TASK-14052] Prod release 105 (#1122)

* feat: handle send link claims to bank account for peanut users (#1078)

* reafactor: create reusable country list component and use it for all the flows

* feat: reusable user accounts components

* feat: handle different cases based on kyc status for bank claim

* fix: account creation

* chore: add docstring to hooks

* chore: better comments for bank flow manager

* fix: kyc modal closing after tos acceptance issue

* fix: remove bank acc caching from withdraw flow

* fix: update confirm claim modal copy

* fix: remove bank acc caching from claim flow

* fix: navheader title

* remove duplicate debounce code and use `useDebounce` hook instead (#1079)

* Landing page v2.1 (#1089)

* lpv2.1 part 1

* Add exchange widget

* add and integrate exchange API

* add yourMoney component bg

* update landing countries svg

* integrate frankfurter API

* fixes and improvements

* decrease hero section height

* allow max 2 decimal places

* Add `/exchange` route

* fix: overlay

* make destination amount editable and bugg fixes

* some fixes & currency improvements

* crucial commit

* fix checkmark, font size and weight

---------

Co-authored-by: Hugo Montenegro <[email protected]>

* [TASK-13186] refactor: use networkName instead of axelarChainName (#1095)

* refactor: use networkName instead of axelarChainName

* fix: types

* fix: onramp currency (#1096)

* fix: stretched favicon (#1099)

* [TASK-13971] fix: scientific notation in eip681 parsing (#1097)

* fix: scientific notation in eip681 parsing

* fix: qr handling tests

* fix: peanut sdk mock

* pull iban hotfix (#1100)

* fix: claim flow bugs (#1102)

* fix: cross chain claim

* fix: full name issue on confirm bank claim view

* fix: back navigation on desktop views

* Fix back button not working on /profile (#1101)

* Fix back button not working

* fix public profile page

* extract internal navigation logic to utility function

* fix: send link claims to us bank accounts (#1108)

* fix: usa bank account claims

* fix: show bank account details in confirm claim view

* Sync Landing page changes (#1111)

* reduce clouds size and update font

* fix: hero section responsiveness issue

* fix: formatting errors

* add currency animation

* fix: us bank claims after kyc for logged in users (#1112)

* fix: trim account form inputs for spaces (#1114)

* [TASK-14107] fix: don't allow claiming on xChain if route is not found (#1115)

* fix: don't allow claiming on xChain if route is not found

* fix(claim): use correct decimals for min receive amount

* feat: handle redirect uri when on unsupported browsers (#1117)

* feat: handle redirect uri when on unsupported browsers

* fix: confirm bank claim ui rows for iban guest claim

* remove animation (#1118)

* fix: formatting

---------

Co-authored-by: Kushagra Sarathe <[email protected]>
Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

* fix: bank claim flow runtime error (#1138)

* hotfix: make iban non optional (#1139)

* fix: bank claim flow runtime error

* fix: dont have iban as optional

* fix: merge conflicts

* fix: merge external account with bank details (#1140)

* fix: add id to external account (#1142)

* added tg footer (#1144)

* Hotfix : add missing countries - claim as guest flow (#1146)

* fix: add missing countries

* remove duplicate comment

* fix: show error on dynamic bank account form (#1147)

* fix: Invalid IBAN for UK (#1151)

---------

Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Juan José Ramírez <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>

---------

Co-authored-by: Mohd Zishan <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>
Co-authored-by: Juan José Ramírez <[email protected]>
Co-authored-by: Juan José Ramírez <[email protected]>
Co-authored-by: Hugo Montenegro <[email protected]>
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