feat: update send router#1364
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughRenames SearchResultCard → ActionListCard and updates all usages; removes RouterViewWrapper and SearchResults; adds geolocation-based payment filtering hook and integrates it into ActionList and SendRouter; adds avatar tiny size; adjusts withdraw/send flows to propagate ?method send-flow param; minor icon and constant updates. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
src/components/Global/Icons/user.tsx (1)
4-6: Optional: prefer props-driven sizing and add a11y defaults.To avoid hard-coding size and to keep decorative icons out of the a11y tree, consider:
- Let consumer control width/height entirely.
- Add aria-hidden and focusable defaults.
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}> + <svg viewBox="0 0 10 10" fill="none" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" {...props}>src/hooks/useRecentUsers.ts (1)
21-25: Defensive null-safety for username comparison.Guard against undefined account.username before toLowerCase to avoid edge-case crashes.
- const isDuplicate = acc.some( - (user) => - user.userId === account.userId || user.username.toLowerCase() === account.username.toLowerCase() - ) + const accountUsernameLc = account.username?.toLowerCase() + const isDuplicate = + acc.some((user) => user.userId === account.userId) || + (accountUsernameLc + ? acc.some((user) => user.username.toLowerCase() === accountUsernameLc) + : false)src/components/Send/views/SendRouter.view.tsx (2)
194-199: IconStack size consistency.iconSize={80} seems large for a right adornment; elsewhere you use 24. Consider 24–32 for visual consistency.
- iconSize={80} + iconSize={24}Also confirm AvatarWithBadge size="tiny" is a supported token; otherwise switch to "extra-small".
91-128: Centralize identifierIcon mapping.Embedding identifierIcon switch in the view duplicates concerns. Prefer enriching ACTION_METHODS (or a factory util) so all consumers render consistent identifiers.
src/hooks/useGeoFilteredPaymentOptions.ts (1)
54-70: Document the need for stableisMethodUnavailablecallback.The
isMethodUnavailablefunction is included in theuseMemodependency array (line 70). If callers pass an inline function or don't memoize it withuseCallback, the memoization will be invalidated on every render.Apply this diff to document this requirement:
/** * hook to filter and sort payment options based on user's geolocation * * filters pix to show only in brazil (BR) and mercado pago to show everywhere except brazil * optionally sorts payment methods to move unavailable ones to the end of the list * * @param options - configuration object * @param options.methods - array of payment methods to filter (defaults to ACTION_METHODS) * @param options.sortUnavailable - whether to sort unavailable methods to the end (defaults to false) - * @param options.isMethodUnavailable - optional function to determine if a method is unavailable for custom sorting logic + * @param options.isMethodUnavailable - optional function to determine if a method is unavailable for custom sorting logic (should be memoized with useCallback to avoid unnecessary recalculations) * @returns object containing filtered and sorted payment methods and loading state
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/components/ActionListCard/index.tsx(3 hunks)src/components/AddMoney/components/CryptoSourceListCard.tsx(2 hunks)src/components/AddMoney/components/DepositMethodList.tsx(2 hunks)src/components/AddMoney/views/TokenSelection.view.tsx(2 hunks)src/components/AddWithdraw/AddWithdrawCountriesList.tsx(2 hunks)src/components/Common/ActionList.tsx(3 hunks)src/components/Common/ActionListDaimoPayButton.tsx(3 hunks)src/components/Common/CountryList.tsx(4 hunks)src/components/Common/CountryListSkeleton.tsx(2 hunks)src/components/Common/SavedAccountsView.tsx(2 hunks)src/components/Global/Icons/user.tsx(1 hunks)src/components/Profile/AvatarWithBadge.tsx(2 hunks)src/components/RouterViewWrapper/index.tsx(0 hunks)src/components/SearchUsers/SearchResults.tsx(0 hunks)src/components/Send/views/SendRouter.view.tsx(2 hunks)src/constants/actionlist.consts.ts(2 hunks)src/hooks/useGeoFilteredPaymentOptions.ts(1 hunks)src/hooks/useRecentUsers.ts(2 hunks)src/hooks/useTranslationViewTransition.ts(0 hunks)
💤 Files with no reviewable changes (3)
- src/components/RouterViewWrapper/index.tsx
- src/components/SearchUsers/SearchResults.tsx
- src/hooks/useTranslationViewTransition.ts
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Applied to files:
src/components/AddWithdraw/AddWithdrawCountriesList.tsx
📚 Learning: 2025-08-26T17:38:37.055Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/components/Common/ActionList.tsx:153-156
Timestamp: 2025-08-26T17:38:37.055Z
Learning: In ActionList.tsx, when there are circular dependency concerns with ACTION_METHODS being imported by other components, the preferred solution is to move ACTION_METHODS to a separate constants file (like src/constants/actionlist.consts.ts) rather than using prop drilling. This centralizes constants management and creates a cleaner dependency graph.
Applied to files:
src/components/Common/ActionList.tsx
📚 Learning: 2025-08-26T15:25:53.328Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1132
File: src/app/[...recipient]/client.tsx:394-397
Timestamp: 2025-08-26T15:25:53.328Z
Learning: In `src/components/Common/ActionListDaimoPayButton.tsx`, the `handleCompleteDaimoPayment` function should not display error messages to users when DB update fails because the Daimo payment itself has succeeded - showing errors would be confusing since the payment was successful.
Applied to files:
src/components/Common/ActionListDaimoPayButton.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.
Applied to files:
src/components/AddMoney/views/TokenSelection.view.tsx
🧬 Code graph analysis (12)
src/components/Send/views/SendRouter.view.tsx (7)
src/redux/hooks.ts (1)
useAppDispatch(5-5)src/hooks/useRecentUsers.ts (1)
useRecentUsers(6-37)src/utils/general.utils.ts (1)
getInitialsFromName(1271-1278)src/constants/actionlist.consts.ts (2)
ACTION_METHODS(14-47)PaymentMethod(5-12)src/components/Global/Icons/Icon.tsx (1)
Icon(209-218)src/hooks/useGeoFilteredPaymentOptions.ts (1)
useGeoFilteredPaymentOptions(30-77)src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/AddWithdraw/AddWithdrawCountriesList.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/hooks/useRecentUsers.ts (1)
src/hooks/useTransactionHistory.ts (1)
useTransactionHistory(51-130)
src/hooks/useGeoFilteredPaymentOptions.ts (2)
src/constants/actionlist.consts.ts (2)
PaymentMethod(5-12)ACTION_METHODS(14-47)src/hooks/useGeoLocation.ts (1)
useGeoLocation(17-71)
src/components/AddMoney/components/DepositMethodList.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Common/ActionList.tsx (2)
src/hooks/useGeoFilteredPaymentOptions.ts (1)
useGeoFilteredPaymentOptions(30-77)src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Common/CountryListSkeleton.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Common/ActionListDaimoPayButton.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Common/SavedAccountsView.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/AddMoney/components/CryptoSourceListCard.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Common/CountryList.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/AddMoney/views/TokenSelection.view.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (25)
src/components/Profile/AvatarWithBadge.tsx (3)
9-9: LGTM! Type definition correctly extended.The 'tiny' size option is properly added to the type union and will be enforced by TypeScript across all usages.
40-40: Verify accessibility for 10px text size.The implementation correctly follows the existing pattern. However, the 10px text size for initials is quite small and may not meet WCAG accessibility guidelines (typically minimum 12px for body text). Please ensure this size is appropriate for your use case and won't be used in contexts where readability is critical.
48-48: LGTM! Icon size correctly proportioned.The 12px icon size maintains the 50% icon-to-container ratio (12/24), consistent with the pattern used in other sizes.
src/hooks/useRecentUsers.ts (2)
7-8: Confirm react-query version for isLoading.If using TanStack Query v5, the pending flag is isPending (not isLoading). Please confirm the version and adjust to avoid stale API usage.
36-36: Return type change verified - all consumers updated correctly.Verification confirms there is only one call site of
useRecentUsersin the codebase (src/components/Send/views/SendRouter.view.tsx:28), and it correctly uses the new object destructuring pattern:const { recentTransactions, isFetchingRecentUsers } = useRecentUsers(). No outdated array-based usage patterns remain.src/components/AddWithdraw/AddWithdrawCountriesList.tsx (1)
287-336: LGTM: ActionListCard migration is correct.Props mapping (title/description/leftIcon/rightContent/position) matches the new component API; disabled state preserved.
src/components/Common/ActionListDaimoPayButton.tsx (1)
165-173: LGTM: Card swap with consistent right content.ActionListCard usage is correct and keeps IconStack on the right; disabled state respects loading. Also aligns with prior learning to avoid surfacing DB-update errors to users.
Based on learnings
src/components/AddMoney/views/TokenSelection.view.tsx (1)
8-8: LGTM! Clean component migration.The update from
SearchResultCardtoActionListCardis well-executed, with all props correctly mapped to the new component interface.Also applies to: 28-45
src/components/AddMoney/components/CryptoSourceListCard.tsx (1)
6-6: LGTM! Consistent refactoring.The migration to
ActionListCardmaintains all existing functionality with correct prop mapping.Also applies to: 25-57
src/components/AddMoney/components/DepositMethodList.tsx (1)
7-7: LGTM! Proper component migration.The switch to
ActionListCardpreserves all props including thedescriptionClassNamecustomization. Well done.Also applies to: 63-94
src/components/Common/CountryListSkeleton.tsx (1)
2-2: LGTM! Skeleton component updated correctly.The migration to
ActionListCardin the skeleton maintains the loading state UI appropriately.Also applies to: 14-20
src/constants/actionlist.consts.ts (2)
7-7: New field added for future extensibility.The optional
identifierIconfield extends thePaymentMethodinterface. This field isn't used in the files under review but may be leveraged elsewhere or reserved for future functionality.
43-43: Verify removal of "Coinbase" from description.The description was updated to remove "Coinbase" from the list of supported exchanges. Please confirm this is intentional (e.g., Coinbase integration removed or temporarily disabled).
src/components/Common/SavedAccountsView.tsx (2)
3-3: LGTM! Good cleanup of unused import.Removing the unused
shortenStringLongimport while addingActionListCardkeeps the imports clean.Also applies to: 11-11
104-126: LGTM! Consistent migration to ActionListCard.The saved accounts rendering correctly uses
ActionListCardwith proper flag and bank icon composition in theleftIconprop.src/components/Common/CountryList.tsx (3)
10-10: LGTM! Import paths updated appropriately.The
SearchInputimport path has been simplified andActionListCardis now correctly imported. This aligns with the broader component reorganization.Also applies to: 20-20
109-123: LGTM! Crypto option card migrated correctly.The crypto deposit/withdraw option now uses
ActionListCardwith appropriate description and icon. Props are correctly mapped.
162-198: LGTM! Country list rendering migrated successfully.Each country item now renders with
ActionListCard, preserving:
- Flag loading optimization (priority/lazy loading)
- Loading state per clicked item
- Disabled state logic
- Custom right content via
getRightContentsrc/components/ActionListCard/index.tsx (1)
7-17: LGTM! Clean component and interface rename.The rename from
SearchResultCardtoActionListCard(and corresponding props interface) is well-executed. The new name better reflects the component's purpose as a generic action list item rather than being tied to search results.All consuming components across the codebase have been updated consistently.
Also applies to: 19-29
src/hooks/useGeoFilteredPaymentOptions.ts (2)
1-4: LGTM!The imports are clean and the 'use client' directive is correctly placed for this client-side hook.
72-76: Remove unnecessarycountryCodefrom return value—it's unused by all consumers.The
countryCodeis returned from this hook but never destructured by either consumer (ActionList.tsx and SendRouter.view.tsx), which only usefilteredMethodsandisLoading. The JSDoc examples similarly never referencecountryCode. Since no consumer accesses this value, it should be removed from the return type rather than kept as dead code.Likely an incorrect or invalid review comment.
src/components/Common/ActionList.tsx (4)
24-24: LGTM!The new imports follow the established pattern of separating constants and using dedicated components. The PaymentMethod type import and useGeoFilteredPaymentOptions hook align well with the geolocation-aware filtering approach.
Based on learnings
Also applies to: 32-33
88-96: LGTM!The
requiresVerificationlogic correctly identifies cases where KYC is needed for bank transactions, with appropriate memoization dependencies.
292-322: LGTM!The
MethodCardcomponent is well-structured and correctly integrates the newActionListCardcomponent. TherequiresVerificationstate is properly displayed with a status badge, and the disabled state is appropriately handled.
195-201: I need to examine the full context of these files to understand the complete flow:Let me check the complete ActionList component to see how it handles the error state and what happens when geolocation fails:
Based on my verification, I've confirmed the concerns in the original review comment. The
useGeoLocationhook properly sets an error state when geolocation fails, and when that happens,isLoadingbecomesfalsewhilecountryCoderemainsnull. This causes the loading state check to pass and render the component without any error feedback to the user. While the filtering logic (countryCode === 'BR') safely handles null values by returning false, the silent failure provides poor UX. The error state is returned by the hook but never checked in ActionList.Check the ActionList component for error state handling and add appropriate error UI feedback.
When geolocation fails, the
errorstate fromuseGeoLocationis set but not displayed. Add a check for the error state to show user feedback before rendering the normal UI. Provide a meaningful message or fallback UI when an error occurs to maintain positive user experience. Consider whether to display the error message inline or handle it through a toast/notification system.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx (1)
72-80: Preserve ?method=bank on redirects to keep send-flow context.When amount/bankAccount guards redirect, you drop the method=bank param, breaking the send context.
Apply:
- router.replace('/withdraw') + router.replace(fromSendFlow ? '/withdraw?method=bank' : '/withdraw') } else if (!bankAccount && amountToWithdraw) { - router.replace(`/withdraw/${country}`) + router.replace(`/withdraw/${country}${fromSendFlow ? '?method=bank' : ''}`)
♻️ Duplicate comments (1)
src/components/Send/views/SendRouter.view.tsx (1)
94-97: Double navigation creates history entries and flicker.This function calls
router.pushon Line 95 and thenredirectToSendByLink()on Line 96, which also callsrouter.push(Line 79) to the same URL. This creates two history entries and potential UI flicker.Apply this diff to remove the redundant navigation:
const handleLinkCtaClick = () => { - router.push(`${window.location.pathname}?view=link`) redirectToSendByLink() }The
redirectToSendByLinkfunction already handles both state reset and navigation.
🧹 Nitpick comments (10)
src/components/Send/views/SendRouter.view.tsx (3)
35-44: IncludefallbackInitialsin the dependency array.The
useCallbackreferencesfallbackInitialsbut doesn't include it in the dependency array. WhilefallbackInitialsis a constant and unlikely to change, this violates React's hooks exhaustive-deps rule.Apply this diff:
- }, [recentTransactions]) + }, [recentTransactions, fallbackInitials])Alternatively, move
fallbackInitialsinside the callback to avoid the dependency:const recentUsersAvatarInitials = useCallback(() => { + const fallbackInitials = ['PE', 'AN', 'UT'] // if we have recent transactions, use them (max 3) if (recentTransactions.length > 0) {
76-80: UseusePathnamehook instead ofwindow.location.pathname.Accessing
window.location.pathnamedirectly is not idiomatic for Next.js and can cause issues during SSR or hydration.Import
usePathnamefromnext/navigation:-import { useRouter, useSearchParams } from 'next/navigation' +import { useRouter, useSearchParams, usePathname } from 'next/navigation'Then update the function:
+ const pathname = usePathname() + const redirectToSendByLink = () => { // reset send flow state when entering link creation flow dispatch(sendFlowActions.resetSendFlow()) - router.push(`${window.location.pathname}?view=link`) + router.push(`${pathname}?view=link`) }
198-275: LGTM! Contacts view is well-structured.The contacts view properly handles loading, list rendering with recent transactions, and an empty state. The
onClickhandlers are correctly wired tohandleUserSelect.Optional: The link CTA card (Lines 249-270) is duplicated from the main view (Lines 281-296). Consider extracting this into a shared component like
<LinkCtaCard onClick={handleLinkCtaClick} />to reduce duplication.src/components/Common/CountryList.tsx (2)
113-126: Avoid non-null assertion on flow; make flow required for add-withdraw or guard at runtime.onClick uses flow! which can be undefined at runtime if the caller forgets flow for add-withdraw usage.
Minimal guard:
- onClick={() => onCryptoClick(flow!)} + onClick={() => flow && onCryptoClick(flow)}Better: make props a discriminated union so flow is required when viewMode is 'add-withdraw'.
type CountryListViewProps = | { viewMode: 'add-withdraw' inputTitle: string onCountryClick: (c: CountryData) => void onCryptoClick?: (flow: 'add' | 'withdraw') => void flow: 'add' | 'withdraw' getRightContent?: (c: CountryData, isSupported: boolean) => ReactNode enforceSupportedCountries?: boolean } | { viewMode: 'claim-request' | 'general-verification' inputTitle: string onCountryClick: (c: CountryData) => void getRightContent?: (c: CountryData, isSupported: boolean) => ReactNode onCryptoClick?: never flow?: never enforceSupportedCountries?: never }
135-143: ISO code mix can misclassify Bridge support; normalize once.You compare country.id directly against a mixed set of alpha-3 keys and alpha-2 values (plus 'US','MX'), which risks mismatches. Normalize both representations before testing.
Apply:
- const isBridgeSupportedCountry = [ - 'US', - 'MX', - ...Object.keys(BRIDGE_ALPHA3_TO_ALPHA2), - ...Object.values(BRIDGE_ALPHA3_TO_ALPHA2), - ].includes(country.id) + const idA3 = country.id.toUpperCase() + const idA2 = (ALL_COUNTRIES_ALPHA3_TO_ALPHA2[idA3] ?? idA3).toUpperCase() + const bridgeA3 = new Set(Object.keys(BRIDGE_ALPHA3_TO_ALPHA2)) + const bridgeA2 = new Set(Object.values(BRIDGE_ALPHA3_TO_ALPHA2)) + const isBridgeSupportedCountry = bridgeA3.has(idA3) || bridgeA2.has(idA2)Optionally lift the two Sets into a useMemo to avoid re-allocating per item.
src/components/AddWithdraw/AddWithdrawCountriesList.tsx (3)
209-212: Encode dynamic query params for Manteca navigation.destination and country can contain spaces/special chars. Encode to avoid malformed URLs.
Apply:
- router.push( - `/withdraw/manteca?country=${account.details.countryName}&destination=${account.identifier}${additionalParams}` - ) + const countryQP = encodeURIComponent(account.details.countryName ?? '') + const destQP = encodeURIComponent(account.identifier ?? '') + router.push(`/withdraw/manteca?country=${countryQP}&destination=${destQP}${additionalParams}`)
41-44: Remove unused isFromSendFlow (or use it).isFromSendFlow is computed but unused; this will trip linters.
- const isFromSendFlow = !!(methodParam && ['bank', 'crypto'].includes(methodParam)) - const isBankFromSend = methodParam === 'bank' && isFromSendFlow + const isBankFromSend = methodParam === 'bank'
171-179: Centralize query param building to avoid subtle bugs.Manual concatenation with '?'/'&' is repeated and error-prone. A tiny helper improves safety and readability.
Example utility:
function withQuery(path: string, qs: Record<string, string | undefined>) { const url = new URL(path, 'https://dummy.base') // base ignored by Next router Object.entries(qs).forEach(([k, v]) => v !== undefined && url.searchParams.set(k, v)) return `${url.pathname}${url.search}${url.hash}` }Usage:
router.push(withQuery(method.path, { method: isBankFromSend ? methodParam : undefined }))Also applies to: 193-201, 203-206, 281-289, 292-294, 308-310
src/app/(mobile-ui)/withdraw/page.tsx (1)
206-234: De-duplicate query string assembly; prefer URLSearchParams/utility.You build method query strings in several branches; a helper would reduce mistakes and keep behavior consistent.
Sketch:
const qp = isFromSendFlow ? { method: methodParam! } : undefined const to = (p: string) => withQuery(p, qp) router.push(to(`/withdraw/${country.path}/bank`)) router.push(to(`/withdraw/crypto`)) router.push(withQuery(`/withdraw/manteca`, { method: selectedMethod.title?.toLowerCase().replace(/\s+/g, '-'), country: selectedMethod.countryPath, ...(isFromSendFlow && { method: methodParam! }) }))src/components/AddWithdraw/AddWithdrawRouterView.tsx (1)
209-212: Encode saved-account params for Manteca route.Same encoding concern as elsewhere: country and destination should be URL-encoded.
Apply:
- const additionalParams = isBankFromSend ? `&method=${methodParam}` : '' - router.push( - `/withdraw/manteca?country=${account.details.countryName}&destination=${account.identifier}${additionalParams}` - ) + const additionalParams = isBankFromSend ? `&method=${encodeURIComponent(methodParam ?? '')}` : '' + const countryQP = encodeURIComponent(account.details.countryName ?? '') + const destQP = encodeURIComponent(account.identifier ?? '') + router.push(`/withdraw/manteca?country=${countryQP}&destination=${destQP}${additionalParams}`)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx(4 hunks)src/app/(mobile-ui)/withdraw/page.tsx(8 hunks)src/components/AddWithdraw/AddWithdrawCountriesList.tsx(9 hunks)src/components/AddWithdraw/AddWithdrawRouterView.tsx(4 hunks)src/components/Common/CountryList.tsx(7 hunks)src/components/Send/views/SendRouter.view.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2025-05-22T15:38:48.586Z
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#869
File: src/app/(mobile-ui)/withdraw/page.tsx:82-88
Timestamp: 2025-05-22T15:38:48.586Z
Learning: The country-specific withdrawal route exists at src/app/(mobile-ui)/withdraw/[...country]/page.tsx and renders the AddWithdrawCountriesList component with flow="withdraw".
Applied to files:
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsxsrc/components/AddWithdraw/AddWithdrawCountriesList.tsxsrc/components/AddWithdraw/AddWithdrawRouterView.tsxsrc/components/Common/CountryList.tsxsrc/app/(mobile-ui)/withdraw/page.tsx
📚 Learning: 2025-09-18T09:30:42.901Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#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)/withdraw/[country]/bank/page.tsxsrc/components/AddWithdraw/AddWithdrawRouterView.tsxsrc/app/(mobile-ui)/withdraw/page.tsx
📚 Learning: 2025-10-02T15:23:01.513Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#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)/withdraw/[country]/bank/page.tsxsrc/app/(mobile-ui)/withdraw/page.tsx
📚 Learning: 2025-09-05T07:31:11.396Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#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/Send/views/SendRouter.view.tsx
📚 Learning: 2024-10-08T20:13:42.967Z
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#413
File: src/context/tokenSelector.context.tsx:118-123
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In the `TokenContextProvider` component within `src/context/tokenSelector.context.tsx`, in the TypeScript React application, when data changes and before calling `fetchAndSetTokenPrice`, it is necessary to reset `selectedTokenData`, `selectedTokenPrice`, `selectedTokenDecimals`, and `inputDenomination` to discard stale data.
Applied to files:
src/app/(mobile-ui)/withdraw/page.tsx
📚 Learning: 2025-10-24T13:44:39.443Z
Learnt from: Zishan-7
PR: peanutprotocol/peanut-ui#1332
File: src/components/Global/TokenAmountInput/index.tsx:141-150
Timestamp: 2025-10-24T13:44:39.443Z
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)/withdraw/page.tsx
🧬 Code graph analysis (4)
src/components/AddWithdraw/AddWithdrawCountriesList.tsx (2)
src/redux/slices/bank-form-slice.ts (1)
bankFormActions(36-36)src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/components/Send/views/SendRouter.view.tsx (9)
src/redux/hooks.ts (1)
useAppDispatch(5-5)src/hooks/useRecentUsers.ts (1)
useRecentUsers(6-37)src/utils/general.utils.ts (1)
getInitialsFromName(1271-1278)src/redux/slices/send-flow-slice.ts (1)
sendFlowActions(101-101)src/constants/actionlist.consts.ts (2)
ACTION_METHODS(14-47)PaymentMethod(5-12)src/components/Global/Icons/Icon.tsx (1)
Icon(209-218)src/hooks/useGeoFilteredPaymentOptions.ts (1)
useGeoFilteredPaymentOptions(30-77)src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)src/components/0_Bruddle/Button.tsx (1)
Button(76-267)
src/components/Common/CountryList.tsx (1)
src/components/ActionListCard/index.tsx (1)
ActionListCard(19-70)
src/app/(mobile-ui)/withdraw/page.tsx (2)
src/context/tokenSelector.context.tsx (1)
tokenSelectorContext(22-45)src/utils/bridge.utils.ts (1)
getCountryFromAccount(83-95)
⏰ 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/Send/views/SendRouter.view.tsx (5)
28-29: LGTM! Backward compatibility maintained.The dual check for both
view=linkandcreateLink=truemaintains backward compatibility while transitioning to the new query param pattern. This is a reasonable approach.
132-169: LGTM! Clean icon extension logic.The
useMemocorrectly extendsACTION_METHODSwith method-specific identifier icons. The empty dependency array is appropriate sinceACTION_METHODSis an imported constant.
171-192: LGTM! Geo-filtering and contacts option properly integrated.The geolocation-based filtering and prepending of the peanut-contacts option is well-implemented. The
useMemocorrectly depends ongeoFilteredMethods.
300-335: LGTM! Send options list properly implemented.The send options list correctly renders each payment method with appropriate right-side content and functional
onClickhandlers. This resolves the previous issue whereonClickhandlers were empty.
100-125: Routes verified and parameters correctly handled.All routes used in
handleMethodClickexist and properly handle query parameters:
/withdrawpage usessearchParams.get('method')to determine flow/withdraw/mantecapage uses bothsearchParams.get('method')andsearchParams.get('country')- Country defaults to 'argentina' when not provided
No issues detected.
src/app/(mobile-ui)/withdraw/[country]/bank/page.tsx (1)
53-63: Points query lost the intended cache-bypass; confirm behavior.Previous behavior deliberately added crypto.randomUUID() to the queryKey to force fresh estimates every render. Current key omits it, which may serve stale estimates.
Based on learnings
If you still need fresh points per render, reintroduce the nonce:
- queryKey: ['calculate-points', 'withdraw', bankAccount?.id, amountToWithdraw], + queryKey: ['calculate-points', 'withdraw', bankAccount?.id, amountToWithdraw, crypto.randomUUID()],Alternatively, document and adjust cache policy (e.g., staleTime: 0, refetchOnMount: 'always') if the change was intentional.
src/components/AddWithdraw/AddWithdrawRouterView.tsx (1)
277-289: Nice: flow-aware gating via enforceSupportedCountries.Passing enforceSupportedCountries={isBankFromSend} aligns the list with send->bank constraints.
Uh oh!
There was an error while loading. Please reload this page.