-
Notifications
You must be signed in to change notification settings - Fork 13
feat: add and withdraw funds to peanut wallet #869
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
""" WalkthroughThis update introduces a comprehensive add and withdraw money flow to the mobile UI, including country-specific and crypto deposit methods. It adds new components for handling multi-step add/withdraw flows, updates asset exports, generalizes card and search result components, and integrates new context providers for withdrawal state management. Several obsolete components are removed. Changes
Possibly related PRs
Suggested reviewers
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 13
🔭 Outside diff range comments (1)
src/app/(mobile-ui)/add-money/[...country]/page.tsx (1)
1-6
: 🛠️ Refactor suggestionPage stub needs to handle dynamic country param.
This catch-all route should useuseParams
fromnext/navigation
to retrieve thecountry
and render the appropriate UI. For instance:+ import { useParams } from 'next/navigation' const AddMoneyCountryPage = () => { + const { country } = useParams() return <div>AddMoneyCountryPage: {country}</div> }
🧹 Nitpick comments (25)
src/assets/exchanges/index.ts (1)
1-3
: Add module-level comment for context.
Per the cursor rules, include a brief lowercase comment summarizing the file’s purpose:// exports SVG logos for supported exchanges
src/components/Global/Icons/exchange-arrows.tsx (2)
4-9
: Allow dynamic icon coloring.
Replace the hardcodedfill="black"
withfill="currentColor"
so that the icon inherits CSScolor
and respects the passedfill
prop.
Apply this diff:- <path - d="M2.66 4.33325L0 6.99992L2.66 9.66658V7.66658H7.33333V6.33325H2.66V4.33325ZM12 2.99992L9.34 0.333252V2.33325H4.66667V3.66658H9.34V5.66658L12 2.99992Z" - fill="black" - /> + <path + d="M2.66 4.33325L0 6.99992L2.66 9.66658V7.66658H7.33333V6.33325H2.66V4.33325ZM12 2.99992L9.34 0.333252V2.33325H4.66667V3.66658H9.34V5.66658L12 2.99992Z" + fill="currentColor" + />
1-2
: Consider adding a brief comment above the component.
Per cursor rules, include a simple lowercase comment explaining the icon’s purpose, e.g.:// arrows indicating fund exchange flow
src/app/(mobile-ui)/add-money/page.tsx (1)
1-5
: Add a simple lowercase comment at the top.
Per cursor rules, include a brief description above the component, e.g.:// entry page for the add money flow
src/app/(mobile-ui)/withdraw/page.tsx (1)
1-7
: This is a placeholder component that needs implementation.This component is currently just a minimal placeholder with a heading. As this PR is marked WIP, consider enhancing this component with actual withdraw functionality in subsequent iterations.
A more complete implementation might include:
export default function WithdrawPage() { return ( - <div> + <div className="h-full w-full space-y-6 p-5"> <h1>Withdraw</h1> + <form className="space-y-4"> + <div> + <label htmlFor="amount" className="block mb-2 text-sm font-medium">Amount</label> + <input type="number" id="amount" className="w-full p-3 border rounded-lg" placeholder="0.00" /> + </div> + <button type="submit" className="w-full p-3 bg-blue-600 text-white rounded-lg">Withdraw Funds</button> + </form> </div> ) }src/components/SearchUsers/SearchResults.tsx (2)
52-56
: Search result card props refactored appropriately.The component has been updated to use the new
SearchResultCard
interface.Consider using optional chaining for a cleaner syntax:
-onClick={() => onUserSelect && onUserSelect(user.username)} +onClick={() => onUserSelect?.(user.username)}🧰 Tools
🪛 Biome (1.9.4)
[error] 56-56: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
91-97
: Recent transactions card props updated consistently.The refactoring has been consistently applied to the recent transactions list as well.
Consider using optional chaining for a cleaner syntax:
-onClick={() => onUserSelect && onUserSelect(user.username)} +onClick={() => onUserSelect?.(user.username)}🧰 Tools
🪛 Biome (1.9.4)
[error] 96-96: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
src/components/AddMoney/views/TokenSelection.view.tsx (2)
22-33
: Consider extracting position calculation logic.The position calculation logic could be extracted into a separate utility function, especially if this pattern is used in multiple components.
- const isFirst = index === 0 - const isLast = index === DEPOSIT_CRYPTO_TOKENS.length - 1 - let position: CardPosition = 'middle' - if (DEPOSIT_CRYPTO_TOKENS.length === 1) { - position = 'single' - } else if (isFirst) { - position = 'first' - } else if (isLast) { - position = 'last' - } + const position = getCardPosition(index, DEPOSIT_CRYPTO_TOKENS.length)You could create a utility function like:
function getCardPosition(index: number, totalItems: number): CardPosition { if (totalItems === 1) return 'single'; if (index === 0) return 'first'; if (index === totalItems - 1) return 'last'; return 'middle'; }
34-34
: Consider adding a comment explaining the token availability logic.It's not immediately clear why only tokens matching
PEANUT_WALLET_TOKEN_SYMBOL
are enabled. A brief comment would help clarify this business rule.- const isDisabled = token.symbol.toLowerCase() !== PEANUT_WALLET_TOKEN_SYMBOL.toLowerCase() + // Only enable the default wallet token (USDT), others are coming soon + const isDisabled = token.symbol.toLowerCase() !== PEANUT_WALLET_TOKEN_SYMBOL.toLowerCase()src/components/AddMoney/views/AddMoneyRouter.view.tsx (2)
16-38
: Consider memoizing the filtered list separately from sorting.The current implementation filters and sorts the list in a single useMemo. Consider separating these operations to avoid unnecessary sorting when only filtering changes.
- const filteredAllMethods = useMemo(() => { + const filteredMethods = useMemo(() => { let methodsToShow if (!searchTerm) { methodsToShow = [...ALL_DEPOSIT_METHODS] } else { methodsToShow = ALL_DEPOSIT_METHODS.filter( (method) => method.title.toLowerCase().includes(searchTerm.toLowerCase()) || method.currency?.toLowerCase().includes(searchTerm.toLowerCase()) || method.description?.toLowerCase().includes(searchTerm.toLowerCase()) ) } + return methodsToShow; + }, [searchTerm]); + const sortedFilteredMethods = useMemo(() => { + return [...filteredMethods].sort((a, b) => { if (a.type === 'crypto' && b.type !== 'crypto') { return -1 } if (b.type === 'crypto' && a.type !== 'crypto') { return 1 } return a.title.toLowerCase().localeCompare(b.title.toLowerCase()) }) - }, [searchTerm]) + }, [filteredMethods])
84-94
: Add aria labels for better accessibility.The empty state and results list should have appropriate ARIA attributes for better screen reader support.
{searchTerm && filteredAllMethods.length === 0 ? ( <EmptyState title="No results found" description="Try searching with a different term." icon="search" + aria-live="polite" /> ) : ( - <div className="flex-1 overflow-y-auto"> + <div className="flex-1 overflow-y-auto" role="list" aria-label="Deposit methods"> <DepositMethodList methods={filteredAllMethods} /> </div> )}src/components/AddMoney/components/CryptoSourceListCard.tsx (2)
12-18
: Consider extracting the Icon component to a separate file.The
Icon
component could be reused in other parts of the application. Consider moving it to a separate file if it's likely to be used elsewhere.
20-57
: Consider adding support for loading and error states.The component doesn't handle loading or error states. Consider adding props and rendering logic for these scenarios.
interface CryptoSourceListCardProps { sources: CryptoSource[] onItemClick: (source: CryptoSource) => void + isLoading?: boolean + error?: string } export const CryptoSourceListCard = ({ sources, onItemClick, + isLoading = false, + error }: CryptoSourceListCardProps) => { return ( <div className="flex flex-col"> + {isLoading && ( + <div className="flex justify-center p-4"> + <span>Loading...</span> + </div> + )} + {error && ( + <div className="flex justify-center p-4 text-red-500"> + {error} + </div> + )} + {!isLoading && !error && sources.length === 0 && ( + <div className="flex justify-center p-4"> + <span>No sources available</span> + </div> + )} {sources.map((source, index) => ( // Existing code... ))} </div> ) }src/components/AddMoney/views/CryptoDepositQR.view.tsx (2)
41-43
: Consider specifying QR code dimensions for better readabilityThe QR code wrapper doesn't have explicit dimensions, which might lead to inconsistent sizing across different screen sizes, affecting readability.
<div className="flex items-center justify-center"> - <QRCodeWrapper url={depositAddress} /> + <QRCodeWrapper url={depositAddress} size={200} /> </div>
49-58
: Add error handling for clipboard operationsThe current implementation doesn't handle potential clipboard API failures. Consider showing an error message if the copy operation fails.
<Button variant="purple" onClick={handleCopyAddress} className="w-full" icon={copied ? 'check' : 'copy'} shadowSize="4" > {copied ? 'Copied!' : 'Copy'} </Button>
You could modify the
handleCopyAddress
function to capture errors:const handleCopyAddress = useCallback(async () => { try { await copyTextToClipboardWithFallback(depositAddress) setCopied(true) setTimeout(() => setCopied(false), 2000) } catch (error) { // Handle error - perhaps with a toast notification console.error('Failed to copy address:', error) } }, [depositAddress])src/components/AddMoney/views/NetworkSelection.view.tsx (2)
15-15
: Simplify interface definitionThe
SelectedNetwork
interface extendsNetworkConfig
without adding any properties, which doesn't provide additional value.-export interface SelectedNetwork extends NetworkConfig {} +export type SelectedNetwork = NetworkConfig;
45-54
: Simplify card position calculation logicThe position calculation logic can be simplified for better readability.
-const isFirst = index === 0 -const isLast = index === allNetworks.length - 1 -let position: CardPosition = 'middle' -if (allNetworks.length === 1) { - position = 'single' -} else if (isFirst) { - position = 'first' -} else if (isLast) { - position = 'last' -} +let position: CardPosition = 'middle' +if (allNetworks.length === 1) { + position = 'single' +} else if (index === 0) { + position = 'first' +} else if (index === allNetworks.length - 1) { + position = 'last' +}src/components/SearchUsers/SearchResultCard.tsx (2)
28-30
: Simplify the click handler logicThe
handleCardClick
function just callsonClick
directly, which doesn't add any value and could be removed.-const handleCardClick = () => { - onClick() -} <Card - onClick={isDisabled ? undefined : handleCardClick} + onClick={isDisabled ? undefined : onClick} position={position} className={twMerge('cursor-pointer hover:bg-gray-50', isDisabled ? 'bg-grey-4' : '', className)} >
33-36
: Enhance disabled state styling for better accessibilityThe current disabled state only changes the background color, which might not be sufficient for accessibility. Consider adding more visual cues and the proper ARIA attributes.
<Card onClick={isDisabled ? undefined : handleCardClick} position={position} - className={twMerge('cursor-pointer hover:bg-gray-50', isDisabled ? 'bg-grey-4' : '', className)} + className={twMerge( + 'cursor-pointer hover:bg-gray-50', + isDisabled ? 'bg-grey-4 cursor-not-allowed opacity-70' : '', + className + )} + aria-disabled={isDisabled} >src/components/AddMoney/components/DepositMethodList.tsx (4)
35-50
: Consider extracting the icon logic into a separate function.The conditional logic for determining the left icon is complex and nested. Extracting this into a dedicated function would improve readability and maintainability.
export const DepositMethodList = ({ methods }: DepositMethodListProps) => { const router = useRouter() const handleMethodClick = (path: string) => { router.push(path) } + const renderMethodIcon = (method: DepositMethod) => { + if (method.type === 'crypto') { + return <AvatarWithBadge icon="wallet-outline" size="extra-small" className="bg-yellow-5" /> + } else if (method.type === 'country') { + return ( + <Image + src={`https://flagcdn.com/w320/${method.id.toLowerCase()}.png`} + alt={`${method.title} flag`} + width={32} + height={32} + className="min-h-8 min-w-8 rounded-full object-fill object-center shadow-sm" + loading="lazy" + onError={(e) => { + // Fallback to text avatar if image fails to load + e.currentTarget.style.display = 'none' + }} + /> + ) + } else { + return <AvatarWithBadge name={method.title} size="extra-small" className="bg-yellow-5" /> + } + } return ( <div className="flex flex-col"> {methods.map((method, index) => ( <SearchResultCard key={method.id} title={method.title} description={method.description || method.currency} - leftIcon={ - method.type === 'crypto' ? ( - <AvatarWithBadge icon="wallet-outline" size="extra-small" className="bg-yellow-5" /> - ) : method.type === 'country' ? ( - <Image - src={`https://flagcdn.com/w320/${method.id.toLowerCase()}.png`} - alt={`${method.title} flag`} - width={32} - height={32} - className="min-h-8 min-w-8 rounded-full object-fill object-center shadow-sm" - loading="lazy" - /> - ) : ( - <AvatarWithBadge name={method.title} size="extra-small" className="bg-yellow-5" /> - ) - } + leftIcon={renderMethodIcon(method)} // ...rest of the component
39-46
: Add error handling for country flag images.The Image component for country flags lacks error handling if a flag image fails to load. Consider adding an onError handler to display a fallback.
<Image src={`https://flagcdn.com/w320/${method.id.toLowerCase()}.png`} alt={`${method.title} flag`} width={32} height={32} className="min-h-8 min-w-8 rounded-full object-fill object-center shadow-sm" loading="lazy" + onError={(e) => { + // Fallback to text avatar if image fails to load + e.currentTarget.style.display = 'none' + // Create a fallback element + const fallback = document.createElement('div'); + fallback.className = "flex items-center justify-center size-8 bg-yellow-5 rounded-full"; + fallback.textContent = method.title.charAt(0).toUpperCase(); + e.currentTarget.parentNode?.appendChild(fallback); + }} />
52-60
: Simplify the position calculation logic.The position calculation can be simplified with a more concise approach.
-position={ - methods.length === 1 - ? 'single' - : index === 0 - ? 'first' - : index === methods.length - 1 - ? 'last' - : 'middle' -} +position={ + methods.length === 1 ? 'single' : + index === 0 ? 'first' : + index === methods.length - 1 ? 'last' : 'middle' +}
28-64
: Consider handling empty methods array explicitly.The component doesn't provide explicit handling for an empty methods array. Consider adding a fallback UI or message when no methods are available.
return ( <div className="flex flex-col"> + {methods.length === 0 && ( + <div className="p-4 text-center text-grey-1"> + No deposit methods available + </div> + )} {methods.map((method, index) => ( // Existing code ))} </div> )src/components/AddMoney/consts/index.ts (2)
23-61
: Consider moving temporary code to a separate file.The comment about
DEPOSIT_CRYPTO_TOKENS
being temporary is informative. Consider moving temporary code to a dedicated file to make it easier to replace later.-// @dev: this is a temporary list of tokens for the deposit screen, using this for a couple of weeks, once x-chain is ready, we will use the x-chain tokens and remove this list, only useful token is USDC here for now +// @dev: this is a temporary list of tokens for the deposit screen. +// TODO: Replace with x-chain tokens once ready
118-1876
: Consider moving the large country list to a separate file.The
ALL_DEPOSIT_METHODS
array is extremely large and dominates this file. Consider moving it to a dedicated file for better maintainability and organization.// In a new file: src/components/AddMoney/consts/countries.ts +import { DepositMethod } from '../components/DepositMethodList' + +export const COUNTRY_DEPOSIT_METHODS: DepositMethod[] = [ + { + id: 'AD', + type: 'country', + title: 'Andorra', + currency: 'EUR', + path: '/add-money/andorra', + }, + // ... rest of the countries +] // In the original file +import { COUNTRY_DEPOSIT_METHODS } from './countries' + -export const ALL_DEPOSIT_METHODS: DepositMethod[] = [ +export const ALL_DEPOSIT_METHODS: DepositMethod[] = [ + { + id: 'crypto', + type: 'crypto', + title: 'Crypto Deposit', + description: 'Use an exchange or your wallet', + path: '/add-money/crypto', + }, + ...COUNTRY_DEPOSIT_METHODS +]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
src/assets/exchanges/binance.svg
is excluded by!**/*.svg
src/assets/exchanges/lemon.svg
is excluded by!**/*.svg
src/assets/exchanges/ripio.svg
is excluded by!**/*.svg
📒 Files selected for processing (26)
.cursorrules
(1 hunks)src/app/(mobile-ui)/add-money/[...country]/page.tsx
(1 hunks)src/app/(mobile-ui)/add-money/crypto/page.tsx
(1 hunks)src/app/(mobile-ui)/add-money/layout.tsx
(1 hunks)src/app/(mobile-ui)/add-money/page.tsx
(1 hunks)src/app/(mobile-ui)/home/page.tsx
(1 hunks)src/app/(mobile-ui)/withdraw/page.tsx
(1 hunks)src/assets/exchanges/index.ts
(1 hunks)src/components/AddFunds/index.tsx
(0 hunks)src/components/AddMoney/components/CryptoSourceListCard.tsx
(1 hunks)src/components/AddMoney/components/DepositMethodList.tsx
(1 hunks)src/components/AddMoney/consts/index.ts
(1 hunks)src/components/AddMoney/views/AddMoneyRouter.view.tsx
(1 hunks)src/components/AddMoney/views/CryptoDepositQR.view.tsx
(1 hunks)src/components/AddMoney/views/NetworkSelection.view.tsx
(1 hunks)src/components/AddMoney/views/TokenSelection.view.tsx
(1 hunks)src/components/Global/ActionModal/index.tsx
(3 hunks)src/components/Global/Icons/Icon.tsx
(6 hunks)src/components/Global/Icons/alert.tsx
(1 hunks)src/components/Global/Icons/exchange-arrows.tsx
(1 hunks)src/components/Global/Icons/plus.tsx
(1 hunks)src/components/Global/TokenSelector/Components/NetworkListItem.tsx
(3 hunks)src/components/PeanutWalletActions/index.tsx
(0 hunks)src/components/SearchUsers/SearchInput.tsx
(2 hunks)src/components/SearchUsers/SearchResultCard.tsx
(1 hunks)src/components/SearchUsers/SearchResults.tsx
(3 hunks)
💤 Files with no reviewable changes (2)
- src/components/PeanutWalletActions/index.tsx
- src/components/AddFunds/index.tsx
🧰 Additional context used
🧬 Code Graph Analysis (7)
src/app/(mobile-ui)/add-money/page.tsx (1)
src/components/AddMoney/views/AddMoneyRouter.view.tsx (1)
AddMoneyRouterView
(11-98)
src/components/Global/Icons/Icon.tsx (3)
src/components/Global/Icons/plus.tsx (1)
PlusIcon
(3-10)src/components/Global/Icons/exchange-arrows.tsx (1)
ExchangeArrowsIcon
(3-10)src/components/Global/Icons/alert.tsx (1)
AlertIcon
(3-10)
src/components/Global/ActionModal/index.tsx (1)
src/components/0_Bruddle/Button.tsx (1)
ButtonProps
(21-29)
src/components/AddMoney/views/CryptoDepositQR.view.tsx (2)
src/utils/general.utils.ts (1)
copyTextToClipboardWithFallback
(384-410)src/components/0_Bruddle/Button.tsx (1)
Button
(65-97)
src/components/AddMoney/components/CryptoSourceListCard.tsx (2)
src/components/AddMoney/consts/index.ts (1)
CryptoSource
(7-14)src/components/SearchUsers/SearchResultCard.tsx (1)
SearchResultCard
(18-62)
src/components/AddMoney/components/DepositMethodList.tsx (1)
src/components/SearchUsers/SearchResultCard.tsx (1)
SearchResultCard
(18-62)
src/components/AddMoney/consts/index.ts (1)
src/components/AddMoney/components/DepositMethodList.tsx (1)
DepositMethod
(7-15)
🪛 Biome (1.9.4)
src/components/SearchUsers/SearchResults.tsx
[error] 56-56: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
[error] 96-96: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (30)
src/components/SearchUsers/SearchInput.tsx (3)
5-12
: Good enhancement to make the component more reusable!Adding the optional placeholder prop to the SearchInputProps interface is a good improvement that enhances the component's flexibility and reusability across different contexts.
14-21
: Clean implementation with backwards compatibility.The prop destructuring with default value ensures backward compatibility while allowing customization where needed. This is a good practice.
32-32
: Properly utilizes the new placeholder prop.The placeholder prop is correctly applied to the BaseInput component, replacing the previously hardcoded value.
Since this PR is related to "add/withdraw funds" functionality, consider whether the default value "Name or username" remains appropriate if this component will be used in financial contexts. If you plan to reuse this component for searching transactions or payment methods, you might want a more generic default or context-specific placeholders.
src/assets/exchanges/index.ts (1)
1-3
: Centralized export of exchange logos.
Named exports align with usage in UI components and improve maintainability.src/components/Global/Icons/exchange-arrows.tsx (1)
3-10
: Icon component implementation is correct.
The SVG structure and typing align with other icon components, and spreadingprops
allows flexibility..cursorrules (1)
8-8
: Update adds clear comment guideline.
This new rule ensures any added or updated code includes simple, lowercase comments, improving clarity.src/app/(mobile-ui)/add-money/page.tsx (1)
3-5
: Component properly delegates to the add money router view.
Exporting<AddMoneyRouterView />
as the default aligns with Next.js conventions for page routing.src/components/Global/Icons/alert.tsx (1)
1-10
: Well-implemented SVG icon component.The AlertIcon component is correctly implemented, following React best practices for SVG icons with proper TypeScript typing.
src/components/Global/Icons/plus.tsx (1)
1-10
: Well-implemented SVG icon component.The PlusIcon component is correctly implemented, following React best practices for SVG icons with proper TypeScript typing.
src/app/(mobile-ui)/add-money/layout.tsx (1)
1-6
: Clean and focused layout component.This layout component provides consistent styling for the "Add Money" feature in the mobile UI. The implementation is straightforward and follows React best practices.
src/components/Global/Icons/Icon.tsx (3)
3-3
: Icons are properly imported.The new icons have been correctly imported at the top of the file.
Also applies to: 20-20, 33-33
48-48
: Icon names correctly added to the type definition.The new icon names have been properly added to the
IconName
type definition, which ensures type safety when using these icons.Also applies to: 89-90
138-140
: Icon components correctly mapped.The new icons have been properly mapped to their respective components in the
iconComponents
object.src/components/SearchUsers/SearchResults.tsx (1)
7-7
: New avatar component imported.The
AvatarWithBadge
component is imported to replace the previous avatar implementation.src/components/Global/ActionModal/index.tsx (3)
1-1
: Button props interface simplified.The
ActionModalButtonProps
now extendsButtonProps
directly, which reduces code duplication and makes the interface more maintainable. Good refactoring.Also applies to: 8-11
99-99
: Modal background styling updated.The modal panel background has been changed to a solid white background. This ensures consistent appearance across the application.
128-131
: Checkbox container and label alignment improved.The spacing and alignment of the checkbox container and label have been adjusted for better visual appearance.
src/components/Global/TokenSelector/Components/NetworkListItem.tsx (4)
18-19
: Props extension enhances component flexibility.Adding
rightContent
andtitleClassName
props improves the component's reusability by allowing customization of both the title styling and right side content.
64-64
: Simplified image styling logic.Removing the conditional styling for the image's
rounded-full
class makes the code more consistent and easier to maintain.
72-74
: Enhanced title styling flexibility.Using
twMerge
to combine default styling with custom classes passed viatitleClassName
is a good practice, allowing for styling customization while maintaining baseline styles.
77-83
: Improved right content rendering logic.The conditional rendering now properly handles three cases: showing a "soon" badge for upcoming networks, displaying custom right content when provided, or falling back to the default chevron icon.
src/components/AddMoney/views/TokenSelection.view.tsx (1)
10-13
: Well-defined props interface.The props interface clearly defines the component's contract with its parent, making it easier to understand how to use this component.
src/components/AddMoney/views/NetworkSelection.view.tsx (1)
56-72
: 🛠️ Refactor suggestionAdd null/undefined checks for network data
The code accesses properties from
squidChainDetails
without checking if it exists first, which could lead to runtime errors if a network ID isn't found in the context data.const squidChainDetails = supportedSquidChainsAndTokens[network.chainId] +const networkName = squidChainDetails?.axelarChainName ?? network.name +const networkIcon = squidChainDetails?.chainIconURI ?? network.iconUrl +const networkId = squidChainDetails?.chainId ?? network.chainId return ( <NetworkListItem key={index} - chainId={squidChainDetails?.chainId ?? network.chainId} - name={squidChainDetails?.axelarChainName ?? network.name} - iconUrl={squidChainDetails?.chainIconURI ?? network.iconUrl} + chainId={networkId} + name={networkName} + iconUrl={networkIcon} isComingSoon={isComingSoon} onClick={() => onNetworkSelect({ - chainId: squidChainDetails?.chainId ?? network.chainId, - name: squidChainDetails?.axelarChainName ?? network.name, - iconUrl: squidChainDetails?.chainIconURI ?? network.iconUrl, + chainId: networkId, + name: networkName, + iconUrl: networkIcon, }) }Likely an incorrect or invalid review comment.
src/app/(mobile-ui)/add-money/crypto/page.tsx (1)
70-76
: Inconsistent back navigation behavior from QR screenThe function
handleBackToNetworkSelectionFromQR
has inconsistent behavior: for exchanges, it goes back to source selection, but for other sources, it goes back to network selection. This might be confusing for users.Consider making the back navigation more consistent, or providing a clearer explanation for this differentiated behavior:
const handleBackToNetworkSelectionFromQR = () => { - if (selectedSource?.type === 'exchange') { - setCurrentStep('sourceSelection') - } else { - setCurrentStep('networkSelection') - } + // Always go back to the previous step + setCurrentStep('riskModal') + + // Alternative: Add a comment explaining the different behavior + // For exchanges, we go back to the beginning because [reason] + // if (selectedSource?.type === 'exchange') { + // setCurrentStep('sourceSelection') + // } else { + // setCurrentStep('networkSelection') + // } }src/components/SearchUsers/SearchResultCard.tsx (1)
46-58
: Clarify the purpose of the Button in the right contentThe
Button
inside the right side doesn't have a clear purpose or behavior; it's styled like a button but doesn't have its own click handler. Consider either making it functional or using a simpler visual element if it's just for decoration.{rightContent ? ( rightContent ) : ( <Button shadowSize="4" size="small" className="h-6 w-6 rounded-full p-0 shadow-[0.12rem_0.12rem_0_#000000]" + onClick={(e) => { + e.stopPropagation(); // Prevent triggering the card's onClick + onClick(); // Trigger the same action as clicking the card + }} > <div className="flex size-7 items-center justify-center"> <Icon name="chevron-up" className="h-9 rotate-90" /> </div> </Button> )}Alternatively, if this is purely decorative:
{rightContent ? ( rightContent ) : ( - <Button - shadowSize="4" - size="small" - className="h-6 w-6 rounded-full p-0 shadow-[0.12rem_0.12rem_0_#000000]" - > - <div className="flex size-7 items-center justify-center"> - <Icon name="chevron-up" className="h-9 rotate-90" /> - </div> - </Button> + <div className="flex size-7 items-center justify-center"> + <Icon name="chevron-up" className="h-9 rotate-90" /> + </div> )}src/components/AddMoney/components/DepositMethodList.tsx (2)
1-6
: LGTM - Proper imports and client directive.The imports are appropriate for the component needs and the 'use client' directive is correctly placed at the top of the file.
7-15
: Well-structured interface definition.The
DepositMethod
interface is well-defined with clear property types and proper export for reuse. The optional properties are correctly marked with?
.src/components/AddMoney/consts/index.ts (3)
7-21
: Well-structured interface definitions.The interfaces for
CryptoSource
andCryptoToken
are well-defined with appropriate property types and optional flags.
63-116
: Good organization of crypto sources.The separation into exchanges and wallets is well-structured and the inclusion of generic "other" options is a good practice.
187-188
: Missing currency for Antarctica.Antarctica doesn't have its own currency, but the empty string could cause display issues. Consider using a placeholder or the currency of the relevant administrative territory.
{ id: 'AQ', type: 'country', title: 'Antarctica', - currency: '', + currency: 'USD', // Or another appropriate fallback path: '/add-money/antarctica', },
setSearchTerm('') | ||
} | ||
|
||
// todo: save recent methods in local storage |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Implement the TODO item for persisting recent methods.
The TODO comment about saving recent methods in local storage should be addressed for a complete implementation.
🏁 Script executed:
#!/bin/bash
# Check if there are other TODOs related to local storage in the codebase
rg -i "todo.*local storage" --glob "*.{ts,tsx,js,jsx}"
Length of output: 160
Implement persistence for recent payment methods
The // todo: save recent methods in local storage
comment in
src/components/AddMoney/views/AddMoneyRouter.view.tsx (line 48) remains unaddressed. Please implement full support for persisting and retrieving the user’s recent methods:
• On component mount, read any stored methods from localStorage
(or a wrapper) and initialize state.
• On adding/selecting a method, update both state and localStorage
.
• Handle JSON serialization, missing or malformed data, and storage errors gracefully.
• Add unit tests (or integration tests) to verify load/save behavior.
🤖 Prompt for AI Agents
In src/components/AddMoney/views/AddMoneyRouter.view.tsx at line 48, implement
the TODO for saving recent methods in local storage by adding logic to load
stored methods from localStorage when the component mounts and initialize the
state accordingly. Update the state and localStorage whenever a method is added
or selected, ensuring JSON serialization and deserialization are handled safely
with error checks for missing or malformed data. Also, add unit or integration
tests to verify that loading and saving recent methods to localStorage works
correctly.
<CryptoSourceListCard sources={CRYPTO_WALLETS} onItemClick={() => {}} /> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty click handler on crypto wallets
The click handler for wallet items is an empty function, which means clicking on wallets does nothing. If these options are "coming soon" and not functional yet, consider disabling them or showing a message to improve user experience.
<div className="mt-1 flex flex-col gap-2">
- <CryptoSourceListCard sources={CRYPTO_WALLETS} onItemClick={() => {}} />
+ <CryptoSourceListCard
+ sources={CRYPTO_WALLETS.map(wallet => ({ ...wallet, disabled: true }))}
+ onItemClick={(source) => {
+ // Show a "coming soon" toast or modal
+ console.log('Wallet deposits coming soon:', source.name);
+ }}
+ />
</div>
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<CryptoSourceListCard sources={CRYPTO_WALLETS} onItemClick={() => {}} /> | |
</div> | |
<div className="mt-1 flex flex-col gap-2"> | |
<CryptoSourceListCard | |
sources={CRYPTO_WALLETS.map(wallet => ({ ...wallet, disabled: true }))} | |
onItemClick={(source) => { | |
// Show a "coming soon" toast or modal | |
console.log('Wallet deposits coming soon:', source.name); | |
}} | |
/> | |
</div> |
🤖 Prompt for AI Agents
In src/app/(mobile-ui)/add-money/crypto/page.tsx around lines 111 to 112, the
onItemClick handler for CryptoSourceListCard is an empty function, resulting in
no action when wallet items are clicked. Update this by either disabling the
clickable wallet items or implementing a handler that shows a "coming soon"
message or notification to inform users that the feature is not yet available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (2)
src/components/Payment/Views/Status.payment.view.tsx (1)
145-153
: 🛠️ Refactor suggestionUse the supplied
redirectTo
prop for the “Done” button as well
handleDone
always pushes/home
, ignoring the caller-provided navigation target.
This breaks the new add-money flow which expects to land on/add-money
.- const handleDone = () => { - if (!!authUser?.user.userId) { - // reset payment state when done - router.push('/home') + const handleDone = () => { + if (!!authUser?.user.userId) { + // reset payment state when done + router.push(redirectTo || '/home')🧰 Tools
🪛 Biome (1.9.4)
[error] 146-146: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
src/components/Payment/PaymentForm/index.tsx (1)
175-191
:⚠️ Potential issueRecipient check blocks Add-Money flow
canInitiatePayment
unconditionally requires arecipient
even whenisAddMoneyFlow
is true, but the Add-Money journey has no external recipient.
As a result the “Review / Connect Wallet” button may stay disabled, andhandleInitiatePayment
might later pass anundefined
recipient down-stream, causing runtime errors in the initiator hook / backend.- const recipientExists = !!recipient + // No recipient is needed when the user is adding money to their own wallet + const recipientExists = + isAddMoneyFlow ? true : !!recipient
🧹 Nitpick comments (11)
src/components/0_Bruddle/Button.tsx (1)
29-30
: Consider adding documentation for the new propsThese new props enhance the flexibility of the Button component, but they lack documentation comments that explain their purpose and usage. Adding JSDoc comments would help other developers understand how to use these features properly.
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { variant?: ButtonVariant size?: ButtonSize shape?: ButtonShape shadowSize?: ShadowSize shadowType?: ShadowType loading?: boolean icon?: IconName + /** Position of the icon relative to the button text ('left' or 'right') */ iconPosition?: 'left' | 'right' + /** Additional classes to apply to the icon for custom styling */ iconClassName?: string }src/components/Payment/Views/Initial.payment.view.tsx (1)
6-13
: Improved JSX formatting and explicit prop passing.The multi-line JSX formatting improves readability. Explicitly passing
isAddMoneyFlow
andisWithdrawFlow
makes the prop forwarding more obvious, even though these props are already included in{...props}
.While functionally correct, there's some redundancy in explicitly setting props that are already included in the props spread. Consider either:
- Removing the explicit props if they're purely for clarity:
<PaymentForm {...props} isPintaReq={isPintaReq} - isAddMoneyFlow={props.isAddMoneyFlow} - isWithdrawFlow={props.isWithdrawFlow} />
- Or using object destructuring for cleaner code:
-export default function InitialPaymentView(props: PaymentFormProps) { - const isPintaReq = props.token?.symbol === 'PNT' || props.isPintaReq +export default function InitialPaymentView({ + token, isPintaReq: propIsPintaReq, isAddMoneyFlow, isWithdrawFlow, ...otherProps +}: PaymentFormProps) { + const isPintaReq = token?.symbol === 'PNT' || propIsPintaReq return ( <PaymentForm - {...props} + {...otherProps} + token={token} isPintaReq={isPintaReq} isAddMoneyFlow={isAddMoneyFlow} isWithdrawFlow={isWithdrawFlow} /> ) }src/components/Global/PeanutActionDetailsCard/index.tsx (2)
70-75
: Complex conditional rendering for avatar icon.The nested ternary operators make the logic harder to read and maintain.
Consider extracting this logic to a separate helper function for better readability:
+const getAvatarIcon = () => { + if (viewType === 'SUCCESS') return 'check' + if (recipientType !== 'USERNAME' || transactionType === 'ADD_MONEY') return 'wallet-outline' + return undefined +} <AvatarWithBadge - icon={ - viewType === 'SUCCESS' - ? 'check' - : recipientType !== 'USERNAME' || transactionType === 'ADD_MONEY' - ? 'wallet-outline' - : undefined - } + icon={getAvatarIcon()} size={avatarSize} // ... other props />
79-85
: Complex conditional for avatar background color.Similar to the icon logic, the nested ternary makes the code harder to read.
Extract this logic to a helper function:
+const getAvatarBackgroundColor = () => { + if (viewType === 'SUCCESS') return '#29CC6A' + if (transactionType === 'ADD_MONEY') return '#FFC900' + return getColorForUsername(recipientName).backgroundColor +} <AvatarWithBadge // ... other props inlineStyle={{ - backgroundColor: - viewType === 'SUCCESS' - ? '#29CC6A' - : transactionType === 'ADD_MONEY' - ? '#FFC900' - : getColorForUsername(recipientName).backgroundColor, + backgroundColor: getAvatarBackgroundColor(), }} />src/app/(mobile-ui)/add-money/crypto/direct/page.tsx (1)
33-36
: Guard against a null recipient before invokingPaymentPage
If, for any reason,recipientUsername
is stillnull
here (e.g., race condition, delayed search-param hydration) we pass['']
toPaymentPage
, which will inevitably fail URL validation.
Add an early return to be extra safe:-const recipientPathSegments = [recipientUsername ?? ''] +if (!recipientUsername) return null // safety-net +const recipientPathSegments = [recipientUsername]src/components/Payment/Views/Status.payment.view.tsx (1)
181-192
: Micro-copy: clarify the success message
For the add-money flow the sentence reads “You successfully added” without specifying what was added.
Consider appending “funds” (or similar) for clarity:-You {isAddMoneyFlow ? 'successfully added' : +You {isAddMoneyFlow ? 'successfully added funds' :src/app/[...recipient]/client.tsx (1)
28-33
: UnusedisDirectPay
flag – clean up for readability
isDirectPay
is only referenced once (line 88) to decide whether to show the public profile view.
All other logic now hinges on theflow
prop directly. Removing the redundant boolean will simplify mental parsing.- const isDirectPay = flow === 'direct_pay' - const isWithdrawFlow = flow === 'withdraw' - const isAddMoneyFlow = flow === 'add_money' + const isWithdrawFlow = flow === 'withdraw' + const isAddMoneyFlow = flow === 'add_money'Remember to change the check on line 88 from
!isDirectPay
toflow !== 'direct_pay'
.src/hooks/usePaymentInitiator.ts (1)
788-798
: Hard stop whenwagmiAddress
is undefined may block non-EVM add-money wallets
initiatePayment
throws ifwagmiAddress
is falsy. This prevents alternative external-wallet integrations that don’t surface an address via wagmi (e.g., WalletConnect on non-EVM chains in future).
Gracefully fall back tohandleExternalWalletPayment
and let it fail only if an address is truly required.- if (!wagmiAddress) { - console.error('Add Money flow requires an external wallet (WAGMI) to be connected.') - throw new Error('External wallet not connected for Add Money flow.') - } + if (!wagmiAddress) { + console.warn('No wagmi address – attempting external-wallet flow anyway.') + }src/components/Payment/PaymentForm/index.tsx (1)
429-434
: Dead code ‑isTokenSelectorDisabled
always returnsfalse
The memoised function returns
false
in every branch, yet tracks six dependencies.
Either remove the computation entirely or implement the intended disabling rule; otherwise this causes unnecessary re-renders.src/components/Payment/Views/Confirm.payment.view.tsx (2)
251-257
: Header still reads “Send” during Add-Money / Withdraw confirmationThe flow-specific header was updated in
PaymentForm
, but the confirmation view keeps a static “Send” title, leading to UX inconsistency.-<NavHeader title="Send" ... /> +<NavHeader title={isAddMoneyFlow ? 'Add Money' : isPintaReq ? 'Pay' : 'Send'} ... />
311-312
: Hide “From” row when no wagmi address
wagmiAddress
may beundefined
immediately after a refresh; showing an empty address looks broken.-{isAddMoneyFlow && <PaymentInfoRow label="From" value={printableAddress(wagmiAddress ?? '')} />} +{isAddMoneyFlow && wagmiAddress && ( + <PaymentInfoRow label="From" value={printableAddress(wagmiAddress)} /> +)}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (24)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx
(1 hunks)src/app/(mobile-ui)/add-money/crypto/page.tsx
(1 hunks)src/app/(mobile-ui)/pay/[...username]/page.tsx
(1 hunks)src/app/[...recipient]/client.tsx
(6 hunks)src/app/[...recipient]/page.tsx
(2 hunks)src/components/0_Bruddle/Button.tsx
(3 hunks)src/components/AddMoney/components/CryptoSourceListCard.tsx
(1 hunks)src/components/AddMoney/components/DepositMethodList.tsx
(1 hunks)src/components/AddMoney/consts/index.ts
(1 hunks)src/components/Global/ActionModal/index.tsx
(6 hunks)src/components/Global/AddressLink/index.tsx
(2 hunks)src/components/Global/Icons/Icon.tsx
(6 hunks)src/components/Global/Icons/alert.tsx
(1 hunks)src/components/Global/Icons/exchange-arrows.tsx
(1 hunks)src/components/Global/Icons/plus.tsx
(1 hunks)src/components/Global/Icons/switch.tsx
(1 hunks)src/components/Global/PeanutActionDetailsCard/index.tsx
(4 hunks)src/components/Global/TokenSelector/TokenSelector.tsx
(3 hunks)src/components/Payment/PaymentForm/index.tsx
(16 hunks)src/components/Payment/Views/Confirm.payment.view.tsx
(10 hunks)src/components/Payment/Views/Initial.payment.view.tsx
(1 hunks)src/components/Payment/Views/Status.payment.view.tsx
(5 hunks)src/components/Request/direct-request/views/Initial.direct.request.view.tsx
(1 hunks)src/hooks/usePaymentInitiator.ts
(7 hunks)
✅ Files skipped from review due to trivial changes (4)
- src/components/Request/direct-request/views/Initial.direct.request.view.tsx
- src/components/Global/Icons/switch.tsx
- src/app/[...recipient]/page.tsx
- src/components/AddMoney/consts/index.ts
🚧 Files skipped from review as they are similar to previous changes (8)
- src/components/Global/Icons/exchange-arrows.tsx
- src/components/Global/Icons/plus.tsx
- src/app/(mobile-ui)/add-money/crypto/page.tsx
- src/components/Global/Icons/alert.tsx
- src/components/Global/Icons/Icon.tsx
- src/components/Global/ActionModal/index.tsx
- src/components/AddMoney/components/DepositMethodList.tsx
- src/components/AddMoney/components/CryptoSourceListCard.tsx
🧰 Additional context used
🧬 Code Graph Analysis (7)
src/components/0_Bruddle/Button.tsx (1)
src/components/Global/Icons/Icon.tsx (1)
Icon
(146-155)
src/components/Payment/Views/Initial.payment.view.tsx (1)
src/components/Payment/PaymentForm/index.tsx (2)
PaymentFormProps
(51-51)PaymentForm
(53-594)
src/app/[...recipient]/client.tsx (1)
src/redux/hooks.ts (2)
useAppDispatch
(5-5)usePaymentStore
(12-12)
src/app/(mobile-ui)/pay/[...username]/page.tsx (1)
src/app/[...recipient]/client.tsx (1)
PaymentPage
(28-320)
src/components/Global/TokenSelector/TokenSelector.tsx (1)
src/components/Global/Icons/Icon.tsx (1)
Icon
(146-155)
src/components/Global/PeanutActionDetailsCard/index.tsx (2)
src/utils/color.utils.ts (1)
getColorForUsername
(30-47)src/constants/zerodev.consts.ts (1)
PEANUT_WALLET_TOKEN_SYMBOL
(21-21)
src/hooks/usePaymentInitiator.ts (1)
src/services/services.types.ts (1)
TRequestChargeResponse
(165-197)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (20)
src/components/Global/TokenSelector/TokenSelector.tsx (5)
53-53
: Good addition of thedisabled
prop to the interface.Adding the optional
disabled
property to theNewTokenSelectorProps
interface improves component flexibility, allowing it to be controlled in various contexts throughout the "Add Money" flow.
56-56
: LGTM on function signature update.The component signature has been correctly updated to accept the new
disabled
prop, maintaining proper TypeScript typing.
522-522
: Good implementation of the disabled state.The
disabled
prop is correctly passed down to the underlying Button component, enabling proper control of the interactivity state.
537-537
: Appropriate icon change for the "Add Money" context.Changing the icon from "currency" to "plus" is more intuitive for the add money flow, creating better visual affordance for users.
542-542
: Improved text clarity.Updating the placeholder text from "Select Token" to "Select a token" improves readability and grammar.
src/components/0_Bruddle/Button.tsx (1)
107-113
: Good implementation of conditional icon positioningThe implementation cleanly handles the positioning of icons either before or after the button text, and properly merges default icon styling with custom classes. This adds flexibility while maintaining a consistent look and feel.
src/components/Global/AddressLink/index.tsx (3)
12-12
: Good addition of theisLink
prop.This new prop adds flexibility to the component, allowing for non-clickable address displays when needed.
15-15
: The function signature correctly includes the new prop.The default value of
true
forisLink
ensures backward compatibility with existing usage.
45-51
: Clean implementation of conditional rendering.The conditional rendering between a Link and a span element is well implemented, maintaining consistent styling between both variants.
src/app/(mobile-ui)/pay/[...username]/page.tsx (3)
1-1
: Good component import update.The import has been correctly updated to match the renamed component from the client module.
9-9
: Descriptive component renaming.Renaming from
PayPage
toDirectPaymentPage
improves clarity about the component's specific purpose.
17-17
: Improved prop API with flow-based approach.Changing from the boolean
isDirectPay
to a string-basedflow="direct_pay"
is a good design choice that:
- Makes the code more self-documenting
- Provides more flexibility for future flow types
- Aligns with the updated
PaymentPage
implementationThis matches the implementation in
src/app/[...recipient]/client.tsx
which now handles multiple flow types.src/components/Payment/Views/Initial.payment.view.tsx (1)
1-3
: Simplified prop typing with reused type.Good refactoring to directly reuse the
PaymentFormProps
type rather than creating a custom type.src/components/Global/PeanutActionDetailsCard/index.tsx (4)
11-11
: Added support for the new 'ADD_MONEY' transaction type.This change aligns with the broader "Add Money" feature implementation.
42-42
: Appropriate icon selection for 'ADD_MONEY' transaction type.The 'arrow-down' icon is a good choice for representing money being added to an account.
57-57
: Clear title for the new transaction type."Add money to Peanut" clearly communicates the purpose of the transaction.
92-96
: Improved token amount formatting.The logic has been refined to handle different token display formats consistently.
src/hooks/usePaymentInitiator.ts (1)
318-325
:prepareTransactionDetails
early-return can mask errors when Peanut Wallet is connected
If the user has Peanut Wallet connected and chooses an external-wallet add-money flow, the current condition works as intended.
However, in all other cases where Peanut Wallet is connected but the transaction still needs preparation (e.g., token swap / x-chain), the early return prevents gas-fee estimation and leaves the UI in an inconsistent state.Consider tightening the guard:
-if (isPeanutWallet && !isAddMoneyFlowContext) { +// Skip preparation only when we are _both_ using Peanut Wallet +// _and_ the chain & token match (no x-chain / swap). +if (isPeanutWallet && !isAddMoneyFlowContext && !(_isXChain || _diffTokens)) {Make sure
_isXChain
/_diffTokens
are computed before this check.src/components/Payment/PaymentForm/index.tsx (1)
264-274
: Payload may carry an undefined recipientEven after the guard above is fixed,
recipient
can still legally beundefined
for the Add-Money flow.
usePaymentInitiator
(and any backend validation) should not expect a recipient in this case. Make the field optional or omit it entirely when adding funds:- const payload = { - recipient: recipient, + const payload = { + ...(recipient && { recipient }), // only include when present(or adjust the initiator signature accordingly).
src/components/Payment/Views/Confirm.payment.view.tsx (1)
78-86
: External-wallet modal may appear at the wrong time
showExternalWalletConfirmationModal
forces the modal to show wheneverisAddMoneyFlow
istrue
, even if the transaction is processed via Peanut Wallet:return isProcessing && (!isPeanutWallet || isAddMoneyFlow)If a future release supports “Add Money” from Peanut Wallet, this condition will mis-fire.
Consider:-(!isPeanutWallet || isAddMoneyFlow) +(!isPeanutWallet && !isAddMoneyFlow) || (isAddMoneyFlow && !isPeanutWallet)or split the logic for clarity.
Looking good, only thing is country page seems to not be implemented yet signal-2025-05-21-151459.mp4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/components/Payment/PaymentForm/index.tsx (1)
427-463
:isButtonDisabled
logic can be simplifiedThe button disabled state logic has significant overlap with
canInitiatePayment
and could be simplified to reduce duplication.Consider simplifying this logic to derive from
canInitiatePayment
:const isButtonDisabled = useMemo(() => { if (isProcessing) return true if (!!error) return true if (isAddMoneyFlow) { if (!isWagmiConnected) return false // "Connect Wallet" button should be active - return ( - !inputTokenAmount || - parseFloat(inputTokenAmount) <= 0 || - !selectedTokenAddress || - !selectedChainID || - isProcessing - ) + return isProcessing || !inputTokenAmount || parseFloat(inputTokenAmount) <= 0 || !selectedTokenAddress || !selectedChainID } - // Existing logic for non-AddMoneyFlow / non-Pinta (Pinta has its own button logic) - if (!isPintaReq) { - if (!inputTokenAmount || parseFloat(inputTokenAmount) <= 0) return true - if (!isConnected) return true // If not connected at all, disable (covers guest non-Peanut scenarios) - if (isActivePeanutWallet && isXChainPeanutWalletReq) return true // Peanut wallet x-chain restriction - if (!selectedTokenAddress || !selectedChainID) return true // Must have token/chain - } - // Fallback for Pinta or other cases if not explicitly handled above - return false + // For non-add money flows, use canInitiatePayment with additional checks + return !canInitiatePayment || (isActivePeanutWallet && isXChainPeanutWalletReq) }, [ isProcessing, isAddMoneyFlow, isWagmiConnected, inputTokenAmount, selectedTokenAddress, selectedChainID, + canInitiatePayment, isConnected, isActivePeanutWallet, isXChainPeanutWalletReq, isPintaReq, - // Removed canInitiatePayment as it's too broad here ])🧰 Tools
🪛 Biome (1.9.4)
[error] 429-429: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
🧹 Nitpick comments (1)
src/components/Payment/PaymentForm/index.tsx (1)
429-429
: Fix redundant double negationThe static analysis detected unnecessary double negation.
- if (!!error) return true + if (error) return true🧰 Tools
🪛 Biome (1.9.4)
[error] 429-429: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/components/Global/TokenSelector/TokenSelector.tsx
(5 hunks)src/components/Payment/PaymentForm/index.tsx
(17 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/Global/TokenSelector/TokenSelector.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
src/components/Payment/PaymentForm/index.tsx
[error] 429-429: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (9)
src/components/Payment/PaymentForm/index.tsx (9)
38-41
: Good addition of flow-specific prop typesThe addition of
isAddMoneyFlow
andisWithdrawFlow
flags to the PaymentFlowProps interface clearly defines the different payment flow modes the component now supports.
234-238
: Wallet connection logic properly handles add money flowThe conditional check prevents users from proceeding without a connected wallet when in the add money flow, which is essential for funding operations.
312-312
: Feature flag correctly passed to payment initiationThe
isAddMoneyFlow
flag is properly passed to the payment initiator, ensuring the correct payment flow path is followed.
348-355
: Clear button text logic for different flowsThe button text appropriately adapts to the current state - showing "Connect Wallet" when disconnected in add money flow, and "Review" for add/withdraw flows.
368-374
: Button icon logic adds clear visual indicatorsThe wallet icon for the connect button in add money flow provides helpful visual context for users.
512-514
: Dynamic UI header adapts to current flowThe header text now properly changes based on whether the user is adding money, withdrawing, or sending - providing clear context to the user.
516-536
: Well-implemented wallet disconnect buttonThe wallet address display with disconnect option is cleanly implemented, appearing only when relevant (connected in add money flow).
573-575
: Appropriate token selector for add money flowThe token selector appropriately appears only when needed for the add money flow with Wagmi connected.
602-628
: Well-designed wallet disconnect modalThe ActionModal implementation for wallet disconnection provides clear user feedback and confirmation options, enhancing the user experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When depositing with an external wallet the following happens: the Insufficient balance message shows even when we have enough balance, and in some cases it does not show when we dont have enough balance. Check the pay flow to see how we are doing it currently:
signal-2025-05-22-103605_008.mp4
Also on pay flow from an external wallet, the button doesn't disable even when the error shows correctly (this works on staging)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (3)
src/components/Payment/PaymentForm/index.tsx (2)
488-530
: Comprehensive button disabled logic but address past review feedback.The current implementation addresses the logic requirements well, but there's a past review comment about duplicating logic with
canInitiatePayment
. Consider the previous suggestion to derive the disabled state from the existing helper.Additionally, there's a static analysis hint about redundant double-negation:
- if (!!error) return true + if (error) return true🧰 Tools
🪛 Biome (1.9.4)
[error] 490-490: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation(lint/complexity/noExtraBooleanCast)
643-645
: 🛠️ Refactor suggestionAddress token selector disabled logic issue.
This matches a previous review comment about the disabled prop logic being ineffective.
The component is only rendered when
isWagmiConnected
is true, but the disabled condition!isWagmiConnected && isAddMoneyFlow
would never be true in this context.-<TokenSelector viewType="add" disabled={!isWagmiConnected && isAddMoneyFlow} /> +<TokenSelector viewType="add" />src/components/AddMoney/consts/index.ts (1)
1852-1857
:⚠️ Potential issueFix URL-unfriendly characters in path (duplicate issue).
The path for U.S. Minor Outlying Islands still contains periods which are URL-unfriendly, despite being flagged in previous reviews.
{ id: 'UM', type: 'country', title: 'U.S. Minor Outlying Islands', currency: 'USD', - path: 'u.s.-minor-outlying-islands', + path: 'us-minor-outlying-islands', },
🧹 Nitpick comments (2)
src/components/AddMoney/consts/index.ts (2)
23-23
: Update or remove outdated temporary comment.The comment indicates this crypto tokens list is temporary "for a couple of weeks" until x-chain is ready. Since this appears to be in active development, consider updating the timeline or removing the comment if the temporary nature is no longer accurate.
226-1984
: Consider using an external data source for country information.The large static country data array contains information that can become outdated (as evidenced by the currency code issues). Consider using a maintained external library or API for country data to ensure accuracy and reduce maintenance burden.
Some options:
world-countries
npm packagecountry-data
npm package- REST Countries API for dynamic updates
This would help prevent currency code drift and reduce the size of this constants file.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
src/app/(mobile-ui)/add-money/crypto/direct/page.tsx
(1 hunks)src/app/(mobile-ui)/add-money/crypto/page.tsx
(1 hunks)src/components/0_Bruddle/Button.tsx
(3 hunks)src/components/AddMoney/consts/index.ts
(1 hunks)src/components/Claim/Link/Initial.view.tsx
(2 hunks)src/components/Global/ErrorAlert/index.tsx
(1 hunks)src/components/Global/PeanutActionCard/index.tsx
(1 hunks)src/components/Payment/PaymentForm/index.tsx
(18 hunks)src/components/Request/direct-request/views/Initial.direct.request.view.tsx
(2 hunks)src/components/Request/link/views/Create.request.link.view.tsx
(2 hunks)src/components/Send/link/views/Initial.link.send.view.tsx
(2 hunks)src/components/TransactionDetails/TransactionCard.tsx
(2 hunks)src/components/TransactionDetails/TransactionDetailsDrawer.tsx
(4 hunks)src/components/Withdraw/views/Confirm.withdraw.view.tsx
(1 hunks)src/hooks/usePaymentInitiator.ts
(12 hunks)src/hooks/useTransactionHistory.ts
(1 hunks)src/styles/globals.css
(1 hunks)
✅ Files skipped from review due to trivial changes (4)
- src/components/Global/PeanutActionCard/index.tsx
- src/components/Request/link/views/Create.request.link.view.tsx
- src/components/Global/ErrorAlert/index.tsx
- src/hooks/useTransactionHistory.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- src/styles/globals.css
- src/components/Request/direct-request/views/Initial.direct.request.view.tsx
- src/components/Claim/Link/Initial.view.tsx
- src/components/0_Bruddle/Button.tsx
- src/app/(mobile-ui)/add-money/crypto/page.tsx
- src/app/(mobile-ui)/add-money/crypto/direct/page.tsx
- src/components/Withdraw/views/Confirm.withdraw.view.tsx
🧰 Additional context used
🧠 Learnings (1)
src/components/Payment/PaymentForm/index.tsx (1)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#424
File: src/components/Global/TokenSelector/TokenSelector.tsx:197-211
Timestamp: 2024-10-11T01:14:15.489Z
Learning: In `src/components/Global/TokenSelector/TokenSelector.tsx`, when the calculation within functions like `byChainAndText` is not computationally expensive, it's acceptable to avoid using `useCallback` for memoization.
🧬 Code Graph Analysis (2)
src/hooks/usePaymentInitiator.ts (1)
src/services/services.types.ts (1)
TRequestChargeResponse
(165-197)
src/components/AddMoney/consts/index.ts (1)
src/components/Global/Icons/Icon.tsx (1)
IconName
(49-94)
🪛 Biome (1.9.4)
src/components/Payment/PaymentForm/index.tsx
[error] 490-490: Avoid redundant double-negation.
It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation
(lint/complexity/noExtraBooleanCast)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (23)
src/components/Send/link/views/Initial.link.send.view.tsx (2)
132-133
: LGTM! Good UI improvements for the file upload input.The addition of the
h-11
class provides consistent height styling, and changing the placeholder to "Comment" makes the input's purpose clearer to users.
145-145
: LGTM! Improved button text provides better user feedback.Changing from the dynamic
loadingState
to the static "Creating link" text provides more specific and actionable feedback to users about what operation is being performed.src/components/Payment/PaymentForm/index.tsx (9)
40-53
: LGTM! Clean type definitions for new payment flows.The new
PaymentFlowProps
type clearly defines the optional boolean flags for different payment flows, and the extension ofPaymentFormProps
maintains good type safety.
152-232
: Well-structured balance validation refactor with improved error handling.The balance validation logic has been significantly improved with:
- Clear separation between add money flow and regular payment flows
- Proper error handling with try-catch blocks
- Descriptive error messages for different scenarios
- Comprehensive checks for token decimals and balance data
The logic correctly handles the add money flow by strictly checking external wallet balance when connected.
295-299
: Good wallet connection check for add money flow.The early return when Wagmi wallet is not connected in add money flow properly guides users to connect their wallet before proceeding.
373-373
: Payload enhancement for add money flow tracking.The addition of
isAddMoneyFlow
flag to the payment payload enables proper flow tracking in downstream handlers.
409-435
: Well-designed conditional button text and icon logic.The button text and icon logic properly handles different states:
- Shows "Connect Wallet" with wallet icon when disconnected in add money flow
- Shows "Review" for add money and withdraw flows
- Shows "Send" for active Peanut wallet users
The logic is clear and covers all necessary states.
573-584
: Excellent navigation integration for different flows.The
NavHeader
component properly handles navigation back to the appropriate pages based on the flow type, and the dynamic title setting enhances user experience.
586-606
: Well-implemented wallet disconnect functionality.The switch button for Wagmi wallet disconnection is properly designed:
- Only shows during add money flow when Wagmi is connected
- Clear visual styling and interaction handling
- Proper integration with AddressLink component
608-608
: Correct conditional rendering for recipient card.The recipient card is appropriately hidden during add money and withdraw flows since these don't involve sending to specific recipients.
673-699
: Excellent modal implementation for wallet disconnection.The
ActionModal
for Wagmi wallet disconnection is well-designed:
- Clear title and description explaining the action
- Proper button layout with disconnect and cancel options
- Good UX with appropriate styling and callbacks
- Prevents accidental disconnection with explicit confirmation
src/hooks/usePaymentInitiator.ts (8)
48-48
: Good interface extension for add money flow tracking.The addition of the optional
isAddMoneyFlow
boolean to theInitiatePaymentPayload
interface enables proper flow differentiation throughout the payment process.
93-93
: Appropriate state tracking for add money operations.The
currentOperationIsAddMoney
state variable provides necessary context for gas estimation and transaction preparation logic.
163-185
: Well-designed gas estimation logic with proper wallet routing.The gas estimation logic correctly determines the appropriate estimator account based on transaction type:
- Cross-chain transactions always use Wagmi wallet
- Add money operations use Wagmi wallet
- Regular operations fallback to connected wallet type
The error handling provides clear feedback when no valid estimator account is found.
322-324
: Good context setting for transaction preparation.The function signature update and state setting properly tracks the add money flow context for downstream logic.
344-351
: Correct early return for Peanut Wallet in add money flow.The logic correctly identifies that add money flow mandates external wallet usage, even when Peanut Wallet is connected, and skips Peanut Wallet-specific preparation.
799-811
: Enhanced charge state handling for multiple flow types.The charge creation logic properly handles the transition to Confirm view for Pinta requests, add money flow, and external wallet scenarios.
814-823
: Robust add money flow execution with proper validation.The add money flow execution includes:
- Proper validation that Wagmi address is connected
- Clear error messaging for missing external wallet
- Appropriate routing to external wallet payment handler
- Good logging for debugging purposes
948-951
: Useful callback for operation cancellation.The
cancelOperation
callback provides a way to handle user cancellation scenarios with appropriate error messaging and state management.src/components/TransactionDetails/TransactionCard.tsx (2)
9-9
: Good import organization.Moving the import statement to be grouped with other imports improves code organization and readability.
125-125
: Theme consistency improvement approved.The color change from
bg-pink-1
tobg-primary-1
for the pending indicator aligns with the primary theme colors, improving UI consistency.src/components/TransactionDetails/TransactionDetailsDrawer.tsx (2)
141-141
: Verify the sourceView condition change.The condition was changed from
transaction.sourceView === 'status'
totransaction.sourceView === 'history'
. This changes when the "Token and network" information is displayed, which could affect user experience.Please ensure this change is intentional and aligns with the expected behavior for different transaction views.
301-303
: UI consistency improvement approved.The button components are now using the consistent
icon
prop pattern with proper styling instead of manually rendering Icon components. This improves UI consistency and maintainability.Also applies to: 345-347
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (3)
src/components/AddMoney/consts/index.ts (3)
1698-1702
: Update outdated currency code for São Tomé and Príncipe.This currency code issue was flagged in previous reviews but remains unaddressed.
{ id: 'ST', type: 'country', title: 'São Tomé and Príncipe', - currency: 'STD', + currency: 'STN', path: 'sao-tome-and-principe', },
1901-1905
: Update outdated currency code for Venezuela.This currency code issue was flagged in previous reviews but remains unaddressed.
{ id: 'VE', type: 'country', title: 'Venezuela', - currency: 'VEF', + currency: 'VES', path: 'venezuela', },
1860-1864
: Fix URL-unfriendly path for U.S. Minor Outlying Islands.This path issue was flagged in previous reviews but remains unaddressed.
{ id: 'UM', type: 'country', title: 'U.S. Minor Outlying Islands', currency: 'USD', - path: 'u.s.-minor-outlying-islands', + path: 'us-minor-outlying-islands', },
🧹 Nitpick comments (1)
src/components/AddMoney/consts/index.ts (1)
1993-2035
: Consider extracting country-specific method generation logic.While the current implementation works, consider extracting this initialization logic into a separate function or utility for better maintainability and testability.
function buildCountrySpecificMethods(countryData: CountryData[]): Record<string, CountrySpecificMethods> { const methods: Record<string, CountrySpecificMethods> = {} countryData.forEach((country) => { if (country.type === 'country') { // existing logic here } }) return methods } export const COUNTRY_SPECIFIC_METHODS = buildCountrySpecificMethods(countryData)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/app/(mobile-ui)/add-money/crypto/page.tsx
(1 hunks)src/components/AddMoney/components/CryptoSourceListCard.tsx
(1 hunks)src/components/AddMoney/consts/index.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/components/AddMoney/components/CryptoSourceListCard.tsx
- src/app/(mobile-ui)/add-money/crypto/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/components/AddMoney/consts/index.ts (1)
src/components/Global/Icons/Icon.tsx (1)
IconName
(49-94)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Deploy-Preview
🔇 Additional comments (2)
src/components/AddMoney/consts/index.ts (2)
7-150
: Well-structured interface definitions.The type definitions and interfaces are clean, properly typed, and well-organized. Good use of union types and optional properties.
1-6
: Clean imports and file organization.Good organization of imports and proper separation of concerns throughout the file.
id: 'trust-wallet', | ||
name: 'Trust Wallet', | ||
type: 'wallet', | ||
icon: TRUST_WALLET_LOGO, | ||
path: '/add-money/crypto/rainbow', | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect path for Trust Wallet.
Trust Wallet's path incorrectly points to 'rainbow' instead of 'trust-wallet', which will cause incorrect routing.
{
id: 'trust-wallet',
name: 'Trust Wallet',
type: 'wallet',
icon: TRUST_WALLET_LOGO,
- path: '/add-money/crypto/rainbow',
+ path: '/add-money/crypto/trust-wallet',
},
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
id: 'trust-wallet', | |
name: 'Trust Wallet', | |
type: 'wallet', | |
icon: TRUST_WALLET_LOGO, | |
path: '/add-money/crypto/rainbow', | |
}, | |
{ | |
id: 'trust-wallet', | |
name: 'Trust Wallet', | |
type: 'wallet', | |
icon: TRUST_WALLET_LOGO, | |
path: '/add-money/crypto/trust-wallet', | |
}, |
🤖 Prompt for AI Agents
In src/components/AddMoney/consts/index.ts between lines 110 and 115, the path
for the Trust Wallet entry is incorrectly set to '/add-money/crypto/rainbow'.
Update this path to '/add-money/crypto/trust-wallet' to ensure correct routing
for Trust Wallet.
specificWithdrawals.forEach((method) => { | ||
withdrawList.push({ | ||
id: `${countryCode.toLowerCase()}-${method.title.toLowerCase()}-withdraw`, | ||
icon: method.icon as IconName, | ||
title: method.title, | ||
description: method.description, | ||
isSoon: true, | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address potential type safety issue with icon property.
The code assumes method.icon
exists when casting to IconName
, but the countrySpecificWithdrawMethods
type allows icon
to be optional. This could cause runtime issues.
specificWithdrawals.forEach((method) => {
withdrawList.push({
id: `${countryCode.toLowerCase()}-${method.title.toLowerCase()}-withdraw`,
- icon: method.icon as IconName,
+ icon: (method.icon || 'bank') as IconName,
title: method.title,
description: method.description,
isSoon: true,
})
})
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
specificWithdrawals.forEach((method) => { | |
withdrawList.push({ | |
id: `${countryCode.toLowerCase()}-${method.title.toLowerCase()}-withdraw`, | |
icon: method.icon as IconName, | |
title: method.title, | |
description: method.description, | |
isSoon: true, | |
}) | |
}) | |
specificWithdrawals.forEach((method) => { | |
withdrawList.push({ | |
id: `${countryCode.toLowerCase()}-${method.title.toLowerCase()}-withdraw`, | |
icon: (method.icon || 'bank') as IconName, | |
title: method.title, | |
description: method.description, | |
isSoon: true, | |
}) | |
}) |
🤖 Prompt for AI Agents
In src/components/AddMoney/consts/index.ts around lines 2004 to 2012, the icon
property is cast to IconName without checking if method.icon exists, which risks
runtime errors due to its optional type. Fix this by adding a conditional check
to ensure method.icon is defined before casting, or provide a safe fallback
value when method.icon is undefined to maintain type safety.
Uh oh!
There was an error while loading. Please reload this page.