feat: url as state poc#1602
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughReplaces local UI state in the add-money onramp flow with URL-persisted query state using nuqs, wraps app providers with NuqsAdapter, and refactors OnrampFlowContext to remove UI state exposing transient onramp data and flags. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review in depth. Evaluate:
Also, write a very concise testing guide for QA |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 41682 🏁 Script executed: Length of output: 1326 🏁 Script executed: Length of output: 29274 🏁 Script executed: Length of output: 7158 🏁 Script executed: Length of output: 17081 🏁 Script executed: Length of output: 11239 @jjramirezn, I've completed an in-depth review of this PR. Here are my findings: 🚨 Critical Issues1. Missing Data Validation for Deep LinksRisk: HIGH - Can cause runtime errors In if (urlState.step === 'showDetails') {
return <AddMoneyBankDetails />
}Problem: If a user navigates directly to Recommendation: if (urlState.step === 'showDetails') {
if (!onrampData?.transferId) {
// Redirect back to input step if data is missing
setUrlState({ step: 'inputAmount', amount: rawTokenAmount || null })
return <PeanutLoading />
}
return <AddMoneyBankDetails />
}2. Merge Artifact File CommittedRisk: HIGH - Repository hygiene The file Action Required: Delete this file before merging. 3. Amount Validation Can Be BypassedRisk: MEDIUM - Business logic Users can manually set Recommendation: Add validation in the if (urlState.step === 'showDetails') {
// Validate amount is still within bounds
const amount = parseFloat(rawTokenAmount)
if (!amount || amount < minimumAmount) {
setUrlState({ step: 'inputAmount' })
setError({ showError: true, errorMessage: 'Invalid amount' })
return <PeanutLoading />
}
// ... rest of validation
}
|
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
220-228: Redirect to inputAmount when depositDetails is missing to handle navigation back scenarios.When a user navigates directly to
?step=depositDetailsvia browser history, deep link, or page refresh,depositDetailslocal state will be undefined while the URL step persists. The condition at line 220 prevents rendering, but the component returns null at line 230 instead of gracefully redirecting.Add a useEffect to redirect back to inputAmount when
step === 'depositDetails'butdepositDetailsis missing, ensuring consistent UX for these navigation scenarios.
🧹 Nitpick comments (2)
src/app/(mobile-ui)/points/page.tsx.orig (2)
65-68: Missing dependency in useEffect.
fetchUseris called inside useEffect but not included in the dependency array. While this may be intentional for mount-only behavior, it can cause issues iffetchUserreference changes.🔎 Consider adding fetchUser to dependencies or using a ref
useEffect(() => { // Re-fetch user to get the latest invitees list for showing heart Icon fetchUser() - }, []) + }, [fetchUser])If mount-only behavior is truly needed, consider using a ref to track if the effect has run.
109-121: Complex inline calculation could benefit from extraction.The progress bar width calculation is complex with multiple conditions. Consider extracting to a named function or useMemo for readability.
🔎 Suggested extraction
const progressBarWidth = useMemo(() => { if (tierInfo?.data.currentTier >= 2) return 100 if (tierInfo.data.nextTierThreshold <= 0) return 0 const ratio = Math.min(1, tierInfo.data.totalPoints / tierInfo.data.nextTierThreshold) return Math.pow(ratio, 0.6) * 100 }, [tierInfo?.data])
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (9)
package.jsonsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/app/(mobile-ui)/points/page.tsx.origsrc/app/ClientProviders.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsxsrc/context/OnrampFlowContext.tsx
🧰 Additional context used
🧠 Learnings (35)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is used instead of `router.replace` in URL manipulation functions when immediate/synchronous URL updates are required for subsequent actions to read the updated URL parameters.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1089
File: src/components/LandingPage/noFees.tsx:282-285
Timestamp: 2025-08-14T12:46:10.706Z
Learning: In the peanutprotocol/peanut-ui project, loading states are implemented only after they have been properly designed by the design team to ensure consistency across the application.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Applied to files:
src/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsxsrc/context/OnrampFlowContext.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Applied to files:
src/components/AddMoney/components/InputAmountStep.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsx
📚 Learning: 2024-10-07T15:28:25.280Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Applied to files:
src/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsxsrc/context/OnrampFlowContext.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.
Applied to files:
src/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2025-01-16T13:14:40.363Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Applied to files:
src/app/ClientProviders.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsxsrc/context/OnrampFlowContext.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/app/(mobile-ui)/points/page.tsx.origsrc/components/AddMoney/components/AddMoneyBankDetails.tsxsrc/components/AddMoney/views/RhinoDeposit.view.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2024-10-22T18:10:56.955Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:25-25
Timestamp: 2024-10-22T18:10:56.955Z
Learning: In the `src/app/request/pay/page.tsx` file, the `PreviewType` enum values are strings, so when adding `previewType` to `URLSearchParams`, there's no need to convert them to strings.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/context/OnrampFlowContext.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-11-04T17:47:06.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsxsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-23T09:38:04.446Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2024-10-04T13:10:49.199Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-04T13:10:49.199Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/context/OnrampFlowContext.tsx
📚 Learning: 2025-06-22T16:10:53.167Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 915
File: src/hooks/useKycFlow.ts:96-124
Timestamp: 2025-06-22T16:10:53.167Z
Learning: The `initiateKyc` function in `src/app/actions/users.ts` already includes comprehensive error handling with try-catch blocks and returns structured responses with either `{ data }` or `{ error }` fields, so additional try-catch blocks around its usage are not needed.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-05-13T10:05:24.057Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-10-08T17:13:13.155Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1299
File: src/app/(mobile-ui)/points/page.tsx:41-51
Timestamp: 2025-10-08T17:13:13.155Z
Learning: In `src/app/(mobile-ui)/points/page.tsx`, the icon name "invite-heart" is intentionally used (not "inviter-heart") when displaying who invited the current user, as this is a deliberate design choice despite semantic differences with UserHeader usage.
Applied to files:
src/app/(mobile-ui)/points/page.tsx.orig
📚 Learning: 2025-07-24T13:26:10.290Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 1014
File: src/components/Claim/Link/Initial.view.tsx:413-413
Timestamp: 2025-07-24T13:26:10.290Z
Learning: In the peanut-ui repository, the change from `${SQUID_API_URL}/route` to `${SQUID_API_URL}/v2/route` in src/components/Claim/Link/Initial.view.tsx was a typo fix, not an API migration, as the codebase was already using Squid API v2.
Applied to files:
src/app/(mobile-ui)/points/page.tsx.orig
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.
Applied to files:
src/components/AddMoney/components/AddMoneyBankDetails.tsx
📚 Learning: 2025-07-05T16:58:25.340Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Applied to files:
src/context/OnrampFlowContext.tsx
📚 Learning: 2024-10-18T08:54:22.142Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 458
File: src/components/Offramp/Confirm.view.tsx:96-96
Timestamp: 2024-10-18T08:54:22.142Z
Learning: In the `src/components/Offramp/Confirm.view.tsx` file, it's acceptable to include crass or informal language in code comments.
Applied to files:
src/context/OnrampFlowContext.tsx
📚 Learning: 2024-10-24T12:45:22.708Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 478
File: src/components/Request/Create/Views/Initial.view.tsx:169-176
Timestamp: 2024-10-24T12:45:22.708Z
Learning: When calling `handleOnNext` in `src/components/Request/Create/Views/Initial.view.tsx`, it's acceptable to duplicate parameter lists for readability instead of refactoring to avoid duplication.
Applied to files:
src/context/OnrampFlowContext.tsx
📚 Learning: 2025-10-07T10:19:20.077Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1286
File: src/components/MultiStepBankAccountForm/FormInput.tsx:10-10
Timestamp: 2025-10-07T10:19:20.077Z
Learning: The codebase follows a strict policy of avoiding `any` types. Always use proper TypeScript types, particularly from libraries like react-hook-form (RegisterOptions, FieldErrors, UseFormSetValue, etc.) rather than using `any`.
Applied to files:
src/context/OnrampFlowContext.tsx
🧬 Code graph analysis (2)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
src/constants/query.consts.ts (1)
TRANSACTIONS(2-2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (3)
src/interfaces/interfaces.ts (1)
BridgeKycStatus(6-6)src/context/OnrampFlowContext.tsx (1)
useOnrampFlow(90-96)src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)
AddMoneyBankDetails(26-376)
⏰ 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 (17)
src/context/OnrampFlowContext.tsx (3)
29-41: Good documentation for the architectural decision.The documentation clearly explains the separation of concerns: URL-managed state (step/amount via nuqs) vs Context-managed state (transient error, navigation flag, API data). This aids maintainability and aligns with the principle of using URL state for shareable/bookmarkable values.
54-72: LGTM!The state initialization and reset logic are correct. The empty dependency array in
useCallbackis appropriate since the state setters fromuseStateare stable references. The reset function properly clears all context-managed state.
74-85: LGTM!The
useMemodependencies are correct. State values and the memoizedresetOnrampFlowcallback are included, while the stableuseStatesetters are appropriately omitted.package.json (1)
64-64: LGTM!The nuqs library is a well-maintained choice for URL state management in Next.js applications. Version 2.8.x is compatible with Next.js 15+ and React 19.
src/app/ClientProviders.tsx (1)
15-31: LGTM!Correct integration of NuqsAdapter for the Next.js App Router. Placing it as the outermost wrapper ensures URL state is available throughout the component tree.
src/components/AddMoney/views/RhinoDeposit.view.tsx (1)
61-62: LGTM!Adding explicit type annotation for the refetchInterval callback improves type safety and makes the code more self-documenting.
src/components/AddMoney/components/InputAmountStep.tsx (1)
17-17: LGTM!The union type appropriately accommodates both URL-state callbacks (
(value: string) => void) and traditional React state setters. This enables flexibility for the URL-state migration while maintaining backward compatibility.src/components/AddMoney/components/AddMoneyBankDetails.tsx (3)
20-20: LGTM!Appropriate import for read-only URL state consumption in the bank details view.
29-31: Good documentation of URL state source.Clear comments explaining the data source selection pattern (URL for add-money, context for request-fulfillment). This helps maintainability.
79-82: LGTM!The conditional amount sourcing is clean:
amountFromUrl ?? ''for add-money flow (URL-driven)depositInstructions.amountfor request-fulfillment flow (context-driven)This aligns with the broader URL-state architecture in this PR.
src/components/AddMoney/components/MantecaAddMoney.tsx (2)
39-51: LGTM!Well-structured URL state management with:
- Type-safe enum parsing for step and currency
history: 'push'enabling browser back/forward navigation- Sensible defaults when URL params are absent
111-129: LGTM!Good implementation of URL-synced handlers:
handleAmountChange: Usesnullto remove empty values from URL (keeps URLs clean)handleDenominationChange: Validates against allowed currencies before persistingsrc/app/(mobile-ui)/add-money/[country]/bank/page.tsx (4)
39-48: LGTM!Well-structured URL state setup with:
- Type-safe step enum covering the full flow
- Amount as a simple string
history: 'push'for proper navigation
100-116: Good deep-linking support with careful initialization.The pattern of checking
urlState.stepbefore setting initial step correctly supports:
- Deep linking (respects existing URL step)
- Fresh navigation (derives from KYC status)
- Waiting for user fetch before deciding
267-283: Good loading state handling during initialization.Proper handling of the loading state while:
- User is being fetched (
user === null)- Initial step is being determined (
!urlState.step)This prevents flash of wrong content during initialization.
59-59:setErroris actively used and necessary for validation; verify cleanup strategy foronrampData.
setErroris used extensively throughout the component for amount validation (lines 128, 133, 137, 140, 158, 172, 190, 198), so it's not unused.setOnrampDatais correctly called on line 185 to store the API response and is needed by the subsequentAddMoneyBankDetailscomponent.However, the component never calls
resetOnrampFlow()on unmount or when navigating away from the entire onramp flow. If users navigate back to/add-moneyor elsewhere, staleonrampDatapersists in the context. Clarify whether this is intentional (to support re-entry into the flow) or if cleanup is needed.Likely an incorrect or invalid review comment.
src/app/(mobile-ui)/points/page.tsx.orig (1)
1-1: Clarify the purpose of the.origfile extension.This file has a
.origextension, which typically indicates a merge conflict backup file. Before proceeding, confirm whether this is:
- An intentional file that should be committed (in which case, rename it to
page.tsx)- A leftover artifact that should be removed
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
81-95: Amount validation effect is correct, but consider adding a guard in the submit handler.The validation correctly checks against
MIN_MANTECA_DEPOSIT_AMOUNTandMAX_MANTECA_DEPOSIT_AMOUNT. However,handleAmountSubmit(line 131) doesn't re-validate before calling the API. If a user deep-links with an invalid amount and clicks submit before the validation effect runs, the API call could proceed with an invalid amount.Consider adding an early return in
handleAmountSubmit:🔎 Suggested guard in handleAmountSubmit
const handleAmountSubmit = useCallback(async () => { if (!selectedCountry?.currency) return if (isCreatingDeposit) return + + // Re-validate amount before submitting + const paymentAmount = parseUnits(usdAmount || '0', PEANUT_WALLET_TOKEN_DECIMALS) + if (paymentAmount < parseUnits(MIN_MANTECA_DEPOSIT_AMOUNT.toString(), PEANUT_WALLET_TOKEN_DECIMALS) || + paymentAmount > parseUnits(MAX_MANTECA_DEPOSIT_AMOUNT.toString(), PEANUT_WALLET_TOKEN_DECIMALS)) { + return + }src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (2)
28-31: Type definition duplicates pattern from MantecaAddMoney.Both
BridgeBankStephere andMantecaStepin MantecaAddMoney follow the same pattern. Consider extracting a shared utility or type if URL state patterns are being standardized across the codebase.
37-48: URL state setup is consistent with MantecaAddMoney.The pattern is correct. As noted in PR comments, there's opportunity to extract shared URL state logic into a custom hook to reduce duplication between this file and
MantecaAddMoney.tsx.🔎 Example shared hook signature
// hooks/useAddMoneyUrlState.ts type AddMoneyStep = 'inputAmount' | 'kyc' | 'collectUserDetails' | 'showDetails' | 'depositDetails' export function useAddMoneyUrlState<T extends AddMoneyStep>( allowedSteps: T[], options?: { includeCurrency?: boolean } ) { // Shared URL state logic }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
🧰 Additional context used
🧠 Learnings (26)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:279-279
Timestamp: 2025-08-14T08:02:26.705Z
Learning: For hotfixes in the peanut-ui codebase, prefer generic error messages over specific validation error details until the copy can be reviewed with the team, even when the validation functions return detailed error messages.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is used instead of `router.replace` in URL manipulation functions when immediate/synchronous URL updates are required for subsequent actions to read the updated URL parameters.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-22T18:10:56.955Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:25-25
Timestamp: 2024-10-22T18:10:56.955Z
Learning: In the `src/app/request/pay/page.tsx` file, the `PreviewType` enum values are strings, so when adding `previewType` to `URLSearchParams`, there's no need to convert them to strings.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-23T09:38:04.446Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-08-13T18:22:01.941Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1094
File: src/components/AddWithdraw/DynamicBankAccountForm.tsx:0-0
Timestamp: 2025-08-13T18:22:01.941Z
Learning: In the DynamicBankAccountForm component, the countryName parameter from useParams will always resemble a country title, not a URL slug.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-04T13:10:49.199Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-04T13:10:49.199Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-11-04T17:47:06.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-06-22T16:10:53.167Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 915
File: src/hooks/useKycFlow.ts:96-124
Timestamp: 2025-06-22T16:10:53.167Z
Learning: The `initiateKyc` function in `src/app/actions/users.ts` already includes comprehensive error handling with try-catch blocks and returns structured responses with either `{ data }` or `{ error }` fields, so additional try-catch blocks around its usage are not needed.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-05-13T10:05:24.057Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-23T09:38:27.670Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
🧬 Code graph analysis (2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (3)
src/interfaces/interfaces.ts (1)
BridgeKycStatus(6-6)src/context/OnrampFlowContext.tsx (1)
useOnrampFlow(90-96)src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)
AddMoneyBankDetails(26-376)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
src/constants/query.consts.ts (1)
TRANSACTIONS(2-2)
⏰ 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 (7)
src/components/AddMoney/components/MantecaAddMoney.tsx (3)
20-26: Well-structured type definitions for URL state.Good use of
parseAsStringEnumfor type-safe step and currency parsing. The types are clear and self-documenting.Consider extracting
MantecaStepandCurrencyDenominationto a shared types file if they're needed elsewhere, or if you want to share patterns with the bank flow.
37-51: URL state setup looks good.The use of
history: 'push'enables proper browser navigation, and the derived values with defaults (lines 49-51) provide a clean API for consumers.
111-129: Handlers correctly sync state to URL.Good defensive validation in
handleDenominationChangeto ensure only valid currencies are persisted. Usingnullto remove empty values from URL is the correct nuqs pattern.src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (4)
100-116: Initial step determination logic is well-designed.Good approach to:
- Respect existing URL step (enabling deep links)
- Wait for user data before determining initial step
- Route based on KYC status
The effect correctly includes
urlState.stepin dependencies to prevent re-running after step is set.
146-162: Amount handling is correctly implemented.The handler uses
nullto remove empty values from URL, and the validation effect properly validates on change. The separation of concerns is clean.
266-283: Loading state handling is appropriate.The two loading checks serve different purposes:
- Lines 267-269: Initial load while fetching user with no URL step
- Lines 281-283: Fallback while determining initial step
This prevents flickering and ensures smooth UX during initialization.
260-264: KYC modal opening correctly triggered via effect.Unlike the showDetails guard, this correctly uses
useEffectto trigger side effects (modal opening) based on URL state.
…red data (deep link / back navigation)
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (1)
100-116: Consider extracting initial step logic to a shared hook.This initial step determination pattern (respecting URL state, waiting for user data, routing based on KYC status) is likely duplicated across add-money flows. Extracting it to a shared hook would improve maintainability and consistency.
Example structure:
// hooks/useOnrampInitialStep.ts function useOnrampInitialStep(currentStep: string | null, kycStatus: BridgeKycStatus | undefined) { // Returns initial step and loading state }src/components/AddMoney/components/MantecaAddMoney.tsx (3)
39-46: Considerhistory: 'replace'to avoid polluting browser history.Using
history: 'push'creates a new browser history entry for every URL state change, including each keystroke when typing an amount. This can make the browser back button cumbersome for users. For intermediate UI states like amount and currency, consider usinghistory: 'replace'instead.🔎 Suggested change
const [urlState, setUrlState] = useQueryStates( { step: parseAsStringEnum<MantecaStep>(['inputAmount', 'depositDetails']), amount: parseAsString, currency: parseAsStringEnum<CurrencyDenomination>(['USD', 'ARS', 'BRL', 'MXN', 'EUR']), }, - { history: 'push' } + { history: 'replace' } )
119-129: Extract valid currencies to avoid duplication.The
validCurrenciesarray duplicates theCurrencyDenominationtype definition (line 26). If the type is updated, this array must be manually synchronized, creating a maintenance burden.🔎 Suggested refactor
Extract the valid currencies to a shared constant at the top of the file:
// Currency denomination type for URL state type CurrencyDenomination = 'USD' | 'ARS' | 'BRL' | 'MXN' | 'EUR' +const VALID_CURRENCIES: CurrencyDenomination[] = ['USD', 'ARS', 'BRL', 'MXN', 'EUR']Then use it in the handler:
const handleDenominationChange = useCallback( (value: string) => { // Only persist valid currency denominations to URL - const validCurrencies: CurrencyDenomination[] = ['USD', 'ARS', 'BRL', 'MXN', 'EUR'] - if (validCurrencies.includes(value as CurrencyDenomination)) { + if (VALID_CURRENCIES.includes(value as CurrencyDenomination)) { setUrlState({ currency: value as CurrencyDenomination }) } }, [setUrlState] )
131-177: Add explicit validation before non-null assertion on amount.Line 152 uses
amount!with a non-null assertion operator, but if bothusdAmountandcurrencyAmountare empty/undefined, this could pass an invalid value to the API. While the UI likely prevents this scenario, adding an explicit guard improves code safety and clarity.🔎 Suggested guard
const handleAmountSubmit = useCallback(async () => { if (!selectedCountry?.currency) return if (isCreatingDeposit) return + // Validate we have a valid amount + if (!usdAmount || usdAmount === '0.00' || error) { + return + } + // check if we still need to determine KYC status if (isMantecaKycRequired === null) { // still loading/determining KYC status, don't proceed yet return }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
🧰 Additional context used
🧠 Learnings (27)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is used instead of `router.replace` in URL manipulation functions when immediate/synchronous URL updates are required for subsequent actions to read the updated URL parameters.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page.
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 1190
File: src/app/(mobile-ui)/qr-pay/page.tsx:156-176
Timestamp: 2025-09-08T03:13:09.111Z
Learning: In the peanut-ui mobile app, the `/qr-pay` route is only accessed through the DirectSendQR component which always includes the qrCode parameter in the URL when redirecting users to the QR pay page after scanning MERCADO_PAGO or PIX QR codes.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-22T18:10:56.955Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:25-25
Timestamp: 2024-10-22T18:10:56.955Z
Learning: In the `src/app/request/pay/page.tsx` file, the `PreviewType` enum values are strings, so when adding `previewType` to `URLSearchParams`, there's no need to convert them to strings.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-23T09:38:04.446Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/[country]/bank/page.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-23T09:38:27.670Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.tsx:103-111
Timestamp: 2024-10-07T13:42:00.443Z
Learning: When the token price cannot be fetched in `src/components/Request/Pay/Pay.tsx` within the `PayRequestLink` component, set `tokenPriceData.price` to 0 to ensure the UI remains functional. Since Squid uses their own price engine for x-chain fulfillment transactions, this approach will not affect the transaction computation.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-11-04T17:47:06.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-06-22T16:10:53.167Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 915
File: src/hooks/useKycFlow.ts:96-124
Timestamp: 2025-06-22T16:10:53.167Z
Learning: The `initiateKyc` function in `src/app/actions/users.ts` already includes comprehensive error handling with try-catch blocks and returns structured responses with either `{ data }` or `{ error }` fields, so additional try-catch blocks around its usage are not needed.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-05-13T10:05:24.057Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
🧬 Code graph analysis (2)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (4)
src/interfaces/interfaces.ts (1)
BridgeKycStatus(6-6)src/context/OnrampFlowContext.tsx (1)
useOnrampFlow(90-96)src/components/Global/PeanutLoading/index.tsx (1)
PeanutLoading(4-28)src/components/AddMoney/components/AddMoneyBankDetails.tsx (1)
AddMoneyBankDetails(26-376)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
src/constants/query.consts.ts (1)
TRANSACTIONS(2-2)
⏰ 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 (7)
src/app/(mobile-ui)/add-money/[country]/bank/page.tsx (2)
28-48: Clean URL state setup with nuqs.The URL state management is well-structured with proper type safety and enum validation for steps. Using 'push' history mode enables browser navigation, and parsing amount as string is appropriate for decimal inputs.
266-271: Excellent fix for deep-link validation.This useEffect properly guards against accessing showDetails without required onramp data, addressing the critical issue from the previous review. The redirect to inputAmount with the loading state check below (lines 335-339) provides a smooth user experience for deep-link and back-navigation scenarios.
Based on the commit message and PR objectives, this fix successfully prevents crashes when showDetails is accessed directly via deep link or browser navigation.
src/components/AddMoney/components/MantecaAddMoney.tsx (5)
97-102: LGTM - Query invalidation is appropriate.Invalidating the transactions query when entering the deposit details step ensures users see fresh data. The dependencies are correct.
186-191: LGTM - Proper handling of deep link and back navigation edge case.This useEffect correctly addresses the previous review concern about state updates during render. By moving the redirect logic to useEffect, it prevents React warnings and potential render loops while safely guarding against accessing
depositDetailswithout required data.
227-231: LGTM - Safe render guard complements the redirect useEffect.Returning
nullwhendepositDetailsis missing prevents any attempt to render with incomplete data while the redirect useEffect executes. This pattern correctly handles the deep-link edge case.
37-51: URL state pattern is well-implemented for this POC.The URL-based state management using
nuqsis clean and type-safe. The separation between URL-persisted state (step, amount, currency) and transient local state (depositDetails, error, loading) is appropriate. The inline documentation at lines 37-38 showing example URLs is helpful for maintainability.
82-95: The error state is already handled via the submit button's disabled state.The
InputAmountStepcomponent properly disables the submit button when an error exists (line 71:disabled={!!error || isLoading || !parseFloat(tokenAmount)}). This preventshandleAmountSubmitfrom being triggered through the UI when validation fails. An explicit error check inhandleAmountSubmitwould be redundant given the button-level protection already in place.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
139-178: Critical: Add server-side or synchronous validation before API call to prevent amount bypass.As noted in PR objectives, users can deep-link with tiny amounts (e.g.,
?amount=0.01¤cy=USD) and potentially bypass client-side validation. The validation effect on lines 83-96 runs asynchronously onusdAmountchanges, but there's a race window where the submit button could be clicked before the USD equivalent is calculated and validated.Add synchronous validation in
handleAmountSubmitbefore the API call:🔎 Proposed fix
const handleAmountSubmit = useCallback(async () => { if (!selectedCountry?.currency) return if (isCreatingDeposit) return + + // Validate amount before proceeding (synchronous check to prevent bypass) + const amountToValidate = currentDenomination === 'USD' + ? parseFloat(displayedAmount || '0') + : parseFloat(usdAmount || '0') + + if (amountToValidate < MIN_MANTECA_DEPOSIT_AMOUNT) { + setError(`Deposit amount must be at least $${MIN_MANTECA_DEPOSIT_AMOUNT}`) + return + } + if (amountToValidate > MAX_MANTECA_DEPOSIT_AMOUNT) { + setError(`Deposit amount exceeds maximum limit of $${MAX_MANTECA_DEPOSIT_AMOUNT}`) + return + } // check if we still need to determine KYC status if (isMantecaKycRequired === null) {
🧹 Nitpick comments (3)
src/components/Global/AmountInput/index.tsx (1)
133-149: Consider addingsetDisplayedAmountto the dependency array.The
setDisplayedAmountcallback is used inside this effect but not listed in the dependency array. If the parent component recreates this callback on re-render (e.g., withoutuseCallback), the effect may use a stale reference.🔎 Proposed fix
- }, [displayValue, alternativeDisplayValue, displaySymbol, secondaryDenomination]) + }, [displayValue, alternativeDisplayValue, displaySymbol, secondaryDenomination, setDisplayedAmount])src/components/AddMoney/components/MantecaAddMoney.tsx (2)
199-209: Verify prop mapping betweentokenAmount/setTokenAmountand actual values.The naming is potentially confusing:
tokenAmount={displayedAmount}- this is the displayed value (could be ARS, USD, etc.)setTokenAmount={handleUsdAmountChange}- but this handler sets USD amountThis asymmetry (display value in, USD value out) relies on
AmountInputpassing the secondary (USD) amount tosetSecondaryAmount. While functionally correct, consider renaming for clarity or adding a comment explaining the mapping.
51-53: Consider initializingusdAmountfrom URL state when denomination is USD.If a user deep-links with
?amount=100¤cy=USD,usdAmountstarts empty and only gets populated afterAmountInputmounts and triggers its effect. This contributes to the validation timing gap.🔎 Proposed fix
- // Local UI state for tracking both amounts (needed for API call and validation) - const [usdAmount, setUsdAmount] = useState<string>('') - const [localCurrencyAmount, setLocalCurrencyAmount] = useState<string>('') + // Local UI state for tracking both amounts (needed for API call and validation) + // Initialize from URL state if available and denomination matches + const [usdAmount, setUsdAmount] = useState<string>(() => + currentDenomination === 'USD' ? (urlState.amount ?? '') : '' + ) + const [localCurrencyAmount, setLocalCurrencyAmount] = useState<string>(() => + currentDenomination !== 'USD' ? (urlState.amount ?? '') : '' + )
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsxsrc/components/AddMoney/components/MantecaDepositShareDetails.tsxsrc/components/Global/AmountInput/index.tsx
🧰 Additional context used
🧠 Learnings (27)
📓 Common learnings
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1230
File: src/app/(mobile-ui)/withdraw/page.tsx:92-97
Timestamp: 2025-09-18T09:30:42.901Z
Learning: In src/app/(mobile-ui)/withdraw/page.tsx, the useEffect that calls setShowAllWithdrawMethods(true) when amountFromContext exists is intentionally designed to run only on component mount (empty dependency array), not when amountFromContext changes. This is the correct behavior for the withdraw flow where showing all methods should only happen on initial load when an amount is already present.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/AddMoney/components/MantecaDepositShareDetails.tsxsrc/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-14T14:42:54.411Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-12-11T10:13:22.806Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-07T15:25:45.170Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/[country]/[regional-method]/page.tsxsrc/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsx
📚 Learning: 2024-10-23T09:38:04.446Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Applied to files:
src/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsx
📚 Learning: 2024-10-29T12:19:41.968Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsxsrc/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-24T13:44:39.473Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.473Z
Learning: In the `TokenAmountInput` component (`src/components/Global/TokenAmountInput/index.tsx`), the slider feature (controlled by `showSlider` prop) is only shown for USD input mode. When the slider is used with `maxAmount`, the `selectedAmount` is computed in USD and `isInputUsd` is always `true`, so the conversion in `onChange` handles it correctly.
Applied to files:
src/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-22T07:25:59.304Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-29T12:20:47.207Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsx
📚 Learning: 2024-10-07T15:28:25.280Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Applied to files:
src/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-10-29T11:27:59.248Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1368
File: src/components/Common/ActionList.tsx:109-111
Timestamp: 2025-10-29T11:27:59.248Z
Learning: In `src/components/Common/ActionList.tsx`, the `balance` from `useWallet()` hook is always in USDC (as a formatted string), making it directly comparable to USD amounts without conversion. The comparison `Number(balance) >= amountInUsd` is intentional and correct.
Applied to files:
src/components/Global/AmountInput/index.tsxsrc/components/AddMoney/components/InputAmountStep.tsxsrc/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-12-02T17:21:45.515Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 551
File: src/context/walletContext/walletContext.tsx:87-88
Timestamp: 2024-12-02T17:21:45.515Z
Learning: When converting `totalBalance` (in USD) to a `BigInt` balance in `src/context/walletContext/walletContext.tsx`, multiplying by `1e6` is intentional to maintain compatibility with USDC's 6 decimal places. The application displays only 2 decimal places, so this level of precision is sufficient.
Applied to files:
src/components/Global/AmountInput/index.tsx
📚 Learning: 2024-10-07T13:42:00.443Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/InputAmountStep.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1266
File: src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx:46-57
Timestamp: 2025-10-02T15:23:01.513Z
Learning: In the withdraw flow at src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx, the points calculation query intentionally uses crypto.randomUUID() in the queryKey dependency array to bypass React Query caching, ensuring fresh points estimates on every render. This is the intended behavior.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-25T11:33:46.776Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1185
File: src/components/Claim/useClaimLink.tsx:14-0
Timestamp: 2025-09-05T07:31:11.396Z
Learning: In the peanut-ui codebase, `window.history.replaceState` is preferred over `router.replace` when immediate/synchronous URL parameter updates are required, as `router.replace` is asynchronous and doesn't guarantee instant URL changes that subsequent code can rely on. This pattern is used consistently across usePaymentInitiator.ts, Confirm.payment.view.tsx, and useClaimLink.tsx.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-12-02T17:19:18.532Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: Hugo0
Repo: peanutprotocol/peanut-ui PR: 413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2024-10-23T09:38:27.670Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 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/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-05-19T19:40:43.138Z
Learnt from: jjramirezn
Repo: peanutprotocol/peanut-ui PR: 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.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-08-20T09:08:19.266Z
Learnt from: kushagrasarathe
Repo: peanutprotocol/peanut-ui PR: 1112
File: src/components/Claim/Link/views/BankFlowManager.view.tsx:336-343
Timestamp: 2025-08-20T09:08:19.266Z
Learning: In the KYC flow implementation, `setJustCompletedKyc` must be called after `await fetchUser()` in the `handleKycSuccess` callback. Setting `justCompletedKyc` before fetching the user would cause a re-fetching loop because `handleKycSuccess` is set in a useEffect inside the KYC hook, which would cause the UI flow to get stuck in one view.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
📚 Learning: 2025-11-04T17:47:06.328Z
Learnt from: Zishan-7
Repo: peanutprotocol/peanut-ui PR: 1396
File: src/app/(mobile-ui)/home/page.tsx:295-304
Timestamp: 2025-11-04T17:47:06.328Z
Learning: In src/app/(mobile-ui)/home/page.tsx, when closing the KycCompletedModal, updateUserById is called without awaiting to provide instant feedback to the user. This fire-and-forget pattern for modal dismissals and UI preference updates is intentional and consistent across the codebase—user experience with instant UI feedback takes priority over waiting for backend sync operations.
Applied to files:
src/components/AddMoney/components/MantecaAddMoney.tsx
🧬 Code graph analysis (1)
src/components/AddMoney/components/MantecaAddMoney.tsx (1)
src/constants/query.consts.ts (1)
TRANSACTIONS(2-2)
⏰ 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 (8)
src/components/AddMoney/components/MantecaDepositShareDetails.tsx (1)
20-27: Props simplified to align with URL-driven navigation - LGTM.The removal of
sourceandonBackprops in favor ofrouter.back()is appropriate for the URL-state pattern. Since navigation state is now persisted in the URL,router.back()will correctly restore the previous step.Also applies to: 85-85
src/app/(mobile-ui)/add-money/[country]/[regional-method]/page.tsx (1)
18-18: Prop removal aligns with component signature change - LGTM.The removal of
source="regionalMethod"is consistent withMantecaAddMoneybecoming a prop-less component that derives its state from URL params.src/components/AddMoney/components/InputAmountStep.tsx (2)
17-17: Type widening forsetTokenAmountis appropriate.The union type
((value: string) => void) | React.Dispatch<React.SetStateAction<string>>allows both simple callback handlers and React state setters, supporting the URL-driven pattern while maintaining backward compatibility.
22-23: New props for URL-state integration forwarded correctly - LGTM.The
initialDenominationandsetDisplayedAmountprops are properly accepted and forwarded toAmountInput, enabling the parent component to control initial state and track displayed values for URL synchronization.Also applies to: 35-36, 50-55
src/components/Global/AmountInput/index.tsx (1)
71-83: Initial denomination logic is well-implemented.The lazy initializer correctly validates
initialDenominationagainst available denominations and falls back toprimaryDenomination.symbolwhen invalid or not provided. This prevents URL state with invalid currency values from causing issues.src/components/AddMoney/components/MantecaAddMoney.tsx (3)
20-49: URL state setup using nuqs looks good.The use of
parseAsStringEnumfor type-safe step and currency values, combined withhistory: 'push'for browser navigation support, is well-suited for the deep-link and bookmarking requirements. Based on learnings, this aligns with the codebase preference for URL state when synchronous updates are needed.
187-192: Good: Redirect logic moved to useEffect as suggested in past review.This correctly addresses the previous review comment about state updates during render. The redirect now runs as a side effect rather than during the render phase.
230-236: Good defensive guard for missing deposit details.The
if (!depositDetails) return nullguard prevents renderingMantecaDepositShareDetailswithout required data. Combined with the useEffect redirect on lines 187-192, this provides defense-in-depth against invalid deep-link states.
|
@coderabbitai review in depth again Evaluate: risk of introducing new bugs and breaking existing functionality |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 4522 🏁 Script executed: Length of output: 3673 🏁 Script executed: Length of output: 1759 🏁 Script executed: Length of output: 4036 🏁 Script executed: Length of output: 9332 @Hugo0, I've completed a fresh in-depth review of the current state of PR 1602. Here's my comprehensive assessment: 🎉 Improvements Since Last ReviewGreat progress! Several critical issues have been addressed:
🚨 Risk Assessment: MEDIUM (reduced from HIGH)Remaining Risk Areas1. Amount Validation Still Bypassable (MEDIUM Risk)Current state: Input validation exists, but URL manipulation still possible. // Line 136-138: Validates on input
if (amount && amount < minimumAmount) {
setError({ showError: true, errorMessage: `Minimum deposit is ${minimumAmount}.` })
return false
}Problem: User can manually edit URL to Recommendation: Add amount validation to the redirect guard: useEffect(() => {
if (urlState.step === 'showDetails') {
const amount = parseFloat(rawTokenAmount)
if (!onrampData?.transferId || !amount || amount < minimumAmount) {
setUrlState({ step: 'inputAmount' })
if (amount && amount < minimumAmount) {
setError({ showError: true, errorMessage: `Minimum deposit is ${minimumAmount}.` })
}
}
}
}, [urlState.step, onrampData?.transferId, setUrlState, rawTokenAmount, minimumAmount])2. Browser Navigation Edge Cases (LOW-MEDIUM Risk)When users use browser back/forward:
3. Inconsistent Pattern - Request Fulfillment Flow (MEDIUM Risk)
export enum RequestFulfillmentBankFlowStep {
BankCountryList = 'bank-country-list',
DepositBankDetails = 'deposit-bank-details',
OnrampConfirmation = 'onramp-confirmation',
CollectUserDetails = 'collect-user-details',
}This creates:
Impact: Maintenance burden, increased cognitive load, harder onboarding for new developers. 4. No Error Boundaries (LOW Risk)If URL state parsing fails or nuqs encounters issues, there's no graceful degradation. Consider wrapping add-money routes in error boundaries. 5. No Test Coverage (MEDIUM Risk)Zero tests found for these critical flows. This increases regression risk significantly. ⚡ Performance Impact: NEUTRAL to SLIGHTLY POSITIVEPositive Impacts
Neutral Impacts
Performance MeasurementsNo measurable latency regression expected. URL updates are instant, and the validation guards prevent unnecessary API calls. Assessment: ✅ Performance impact is positive overall. 🎨 Code Quality & DRY: GOOD with Missed OpportunitiesPositive Aspects
DRY Violations (MEDIUM Priority)Duplication detected between Both files have nearly identical: const [urlState, setUrlState] = useQueryStates(
{
step: parseAsStringEnum<StepType>([...steps]),
amount: parseAsString,
},
{ history: 'push' }
)
// Redirect guard pattern
useEffect(() => {
if (urlState.step === 'targetStep' && !requiredData) {
setUrlState({ step: 'inputAmount' })
}
}, [urlState.step, requiredData, setUrlState])Recommendation: Extract shared logic: // hooks/useAddMoneyUrlState.ts
export function useAddMoneyUrlState<TStep extends string>({
validSteps,
defaultStep,
additionalParams = {}
}: {
validSteps: TStep[]
defaultStep: TStep
additionalParams?: Record<string, any>
}) {
const [urlState, setUrlState] = useQueryStates(
{
step: parseAsStringEnum<TStep>(validSteps),
amount: parseAsString,
...additionalParams,
},
{ history: 'push' }
)
const step = urlState.step ?? defaultStep
const amount = urlState.amount ?? ''
return {
step,
amount,
urlState,
setUrlState,
rawAmount: urlState.amount
}
}
// Usage in bank/page.tsx
const { step, amount, setUrlState } = useAddMoneyUrlState({
validSteps: ['inputAmount', 'kyc', 'collectUserDetails', 'showDetails'] as const,
defaultStep: 'inputAmount'
})
// Usage in MantecaAddMoney.tsx
const { step, amount, setUrlState } = useAddMoneyUrlState({
validSteps: ['inputAmount', 'depositDetails'] as const,
defaultStep: 'inputAmount',
additionalParams: {
currency: parseAsStringEnum<CurrencyDenomination>(['USD', 'ARS', 'BRL', 'MXN', 'EUR'])
}
})Benefits:
Minor Code Quality Issues
📋 Updated Recommendations (Prioritized)HIGH Priority
MEDIUM Priority
LOW Priority
🎯 Summary
Overall: This PR is in much better shape than the initial review. The critical deep-link validation issues are resolved, and the implementation is solid. The main concerns are:
These are not blockers for merging but should be addressed in follow-up work. Would you like me to:
🧠 Learnings used |
|
@coderabbitai also review the new library nuqs. Is this PR a complete migration to it? Or do we have inconsistent state management now? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 9571 🌐 Web query: 💡 Result: Short answer
Is it production ready?
Sources
@Hugo0, great question! Let me provide a comprehensive analysis of nuqs and the migration status. 📚 About nuqs LibraryBased on my research, nuqs is production-ready and well-suited for this use case: nuqs is a tiny (~5-6KB gzipped) type-safe URL-search-params state manager for React/Next.js that provides:
Verdict on library choice: ✅ Excellent choice for URL-based state management in Next.js. 🔍 Migration Status: PARTIAL (Not Complete)✅ What Now Uses nuqs (URL State)Add-Money flows only:
❌ What Still Uses Context/useState (Old Patterns)Multiple flows NOT migrated:
⚖️ Inconsistency Assessment: MEDIUM-HIGH ConcernCurrent State Management Patterns in Codebase:
Specific Inconsistencies:1. High Impact: Onramp Flows Split 🔴
2. Medium Impact: Developer Confusion 🟡When working on flows, developers must decide:
No clear guidelines exist. 3. Medium Impact: Maintenance Burden 🟡
4. Low Impact: Mixed Context 🟢OnrampFlowContext now has mixed responsibilities:
📋 Recommendations (Prioritized)SHORT TERM (This PR)✅ ACCEPT the partial migration as-is because:
MEDIUM TERM (Follow-up PRs)Priority 1: Migrate Request Fulfillment Flow 🔴 // HIGH PRIORITY - Same domain as add-money
// src/context/RequestFulfillmentFlowContext.tsx
// Should use nuqs for step management like add-money does
Priority 2: Document the Pattern 🟡 # ADR: When to Use URL State vs Context
## Decision
- Multi-step flows with user input → URL state (nuqs)
- Transient app state (errors, loading) → Context
- Pure UI state (modal open/closed) → Component state
## Examples
- ✅ URL State: Onramp flows, withdrawal flows
- ✅ Context: Error handling, transient data
- ✅ Component State: Dropdown open/closedPriority 3: Consider Other Flow Migrations 🟡
LONG TERM (Architecture)Create a Standard Pattern: // hooks/useFlowUrlState.ts
// Shared hook for all multi-step flows
export function useFlowUrlState<TStep>({
steps,
defaultStep,
additionalParams
}) {
// Centralized URL state management
// Consistent validation
// Standard redirect guards
}🎯 SummaryIs this a complete migration? Do we have inconsistent state management?
Should this block the PR?
Most Important Next Step: Would you like me to:
🐰✨ ✏️ Learnings added
🧠 Learnings used |
No description provided.