Conversation
…nut-ui into feat/new-landing-page
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis update introduces several new content sections and marquee components to the landing page, centralizes animation logic with new reusable hooks, and implements a multi-stage scroll-driven animation for a sticky button. The changes add new visual sections, refactor animation code, and expand the set of exported components and hooks. Changes
Possibly related PRs
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (5)
✨ Finishing Touches
🧪 Generate unit tests
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.
Actionable comments posted: 7
🧹 Nitpick comments (10)
src/components/LandingPage/businessIntegrate.tsx (2)
26-27: Consider extracting inline styles to CSS classes.The inline
style={{ fontWeight: 300 }}could be replaced with a Tailwind class likefont-lightfor better maintainability.- style={{ fontWeight: 300 }} + className="relative translate-x-[2px] font-light font-knerd-filled text-[4rem] text-white md:translate-x-[3px] md:text-8xl"
44-49: Consider extracting inline styles to CSS classes.The inline style for
fontWeight: 500andletterSpacing: '-0.5px'could be replaced with Tailwind classes for consistency.- style={{ fontWeight: 500, letterSpacing: '-0.5px' }} + className="mb-8 max-w-xs font-roboto text-xl font-medium leading-tight tracking-tight md:mb-16 md:max-w-none md:text-4xl"src/components/LandingPage/yourMoney.tsx (2)
87-87: Consider simplifying conditional margin logic.The conditional margin logic
${index === 1 ? 'mb-3' : 'mb-4'}could be simplified or moved to a utility function for better readability.- className={`${index === 1 ? 'mb-3' : 'mb-4'} w-full max-w-sm text-left md:text-left`} + className={`mb-4 w-full max-w-sm text-left md:text-left ${index === 1 ? 'md:mb-3' : ''}`}
97-102: Consider extracting inline styles to CSS classes.The inline
letterSpacing: '-0.5px'could be replaced with a Tailwind class for consistency with the design system.- style={{ letterSpacing: '-0.5px' }} + className="w-full max-w-[360px] text-left font-roboto text-lg font-normal leading-relaxed tracking-tight md:text-lg"src/components/LandingPage/securityBuiltIn.tsx (1)
88-88: Remove redundanttext-leftclassThe parent div already handles text alignment with
text-center md:text-left, making thistext-leftclass redundant.- <div className="mb-4 w-full max-w-sm text-left md:text-left"> + <div className="mb-4 w-full max-w-sm">src/components/LandingPage/noFees.tsx (1)
34-34: Replace inline styles with utility classes for consistencyConsider using Tailwind utility classes instead of inline styles for better maintainability and consistency with the rest of the codebase.
- style={{ top: '20%', width: 200 }} + className="absolute left-0 top-[20%] w-[200px]"- style={{ top: '60%', width: 220 }} + className="absolute right-0 top-[60%] w-[220px]"Also applies to: 41-41
src/components/LandingPage/hero.tsx (2)
32-40: Remove unusedrenderSparklefunctionThe
renderSparklefunction is defined but never used (commented out at line 109). Remove it to reduce code clutter.Remove the entire
renderSparklefunction (lines 32-40) since it's not being used.Also applies to: 109-109
98-98: Remove unusedarrowOpacityvariableThe
arrowOpacityvariable is always set to 1. Remove it and use the value directly.- const arrowOpacity = 1 // Always visible const animation = variant === 'primary' ? primaryButtonAnimation : secondaryButtonAnimationAnd update the style props:
- style={{ opacity: buttonVisible ? arrowOpacity : 0, rotate: '8deg' }} + style={{ opacity: buttonVisible ? 1 : 0, rotate: '8deg' }}Also applies to: 50-50, 58-58, 66-66, 74-74
src/components/LandingPage/sendInSeconds.tsx (1)
132-132: Consider using a standard breakpoint or constant for screen width checkThe hardcoded value
1740is arbitrary and doesn't align with standard responsive breakpoints. Consider using a predefined breakpoint or extracting this as a named constant.+const SHOW_EXCLAMATIONS_BREAKPOINT = 1740 // or use a standard XL breakpoint - {screenWidth > 1740 && ( + {screenWidth > SHOW_EXCLAMATIONS_BREAKPOINT && (src/hooks/useAnimations.ts (1)
1-1: Remove unused import.The
useMemoimport is not used anywhere in the file and should be removed to keep the imports clean.-import { useEffect, useState, useMemo } from 'react' +import { useEffect, useState } from 'react'
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (31)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yamlpublic/arrows/small-arrow.svgis excluded by!**/*.svgsrc/assets/illustrations/biometric-protection.svgis excluded by!**/*.svgsrc/assets/illustrations/border-cloud.svgis excluded by!**/*.svgsrc/assets/illustrations/exclamations.svgis excluded by!**/*.svgsrc/assets/illustrations/free-global-transfers.svgis excluded by!**/*.svgsrc/assets/illustrations/get-paid-worldwide.svgis excluded by!**/*.svgsrc/assets/illustrations/got-it-hand-flipped.svgis excluded by!**/*.svgsrc/assets/illustrations/got-it-hand.svgis excluded by!**/*.svgsrc/assets/illustrations/hand-peace.svgis excluded by!**/*.svgsrc/assets/illustrations/hand-waving.svgis excluded by!**/*.svgsrc/assets/illustrations/instantly-send-receive.svgis excluded by!**/*.svgsrc/assets/illustrations/kyc-only-when-required.svgis excluded by!**/*.svgsrc/assets/illustrations/mobile-security-privacy-built-in.svgis excluded by!**/*.svgsrc/assets/illustrations/mobile-send-in-seconds.svgis excluded by!**/*.svgsrc/assets/illustrations/mobile-your-money-anywhere.svgis excluded by!**/*.svgsrc/assets/illustrations/mobile-zero-fees.svgis excluded by!**/*.svgsrc/assets/illustrations/new-hand-token.svgis excluded by!**/*.svgsrc/assets/illustrations/new-hero-description.svgis excluded by!**/*.svgsrc/assets/illustrations/no-hidden-fees.svgis excluded by!**/*.svgsrc/assets/illustrations/pay-anyone-anywhere.svgis excluded by!**/*.svgsrc/assets/illustrations/pay-zero-fees.svgis excluded by!**/*.svgsrc/assets/illustrations/peanut-means.svgis excluded by!**/*.svgsrc/assets/illustrations/security-privacy-built-in.svgis excluded by!**/*.svgsrc/assets/illustrations/self-custodial-design.svgis excluded by!**/*.svgsrc/assets/illustrations/your-money-anywhere.svgis excluded by!**/*.svgsrc/assets/illustrations/zero.svgis excluded by!**/*.svgsrc/assets/iphone-ss/iphone-your-money-1.pngis excluded by!**/*.pngsrc/assets/iphone-ss/iphone-your-money-2.pngis excluded by!**/*.pngsrc/assets/iphone-ss/iphone-your-money-3.pngis excluded by!**/*.pngsrc/assets/scribble.svgis excluded by!**/*.svg
📒 Files selected for processing (12)
src/app/page.tsx(2 hunks)src/assets/illustrations/index.ts(1 hunks)src/components/Global/Layout/index.tsx(0 hunks)src/components/LandingPage/businessIntegrate.tsx(1 hunks)src/components/LandingPage/hero.tsx(4 hunks)src/components/LandingPage/index.ts(1 hunks)src/components/LandingPage/noFees.tsx(1 hunks)src/components/LandingPage/securityBuiltIn.tsx(1 hunks)src/components/LandingPage/sendInSeconds.tsx(1 hunks)src/components/LandingPage/yourMoney.tsx(1 hunks)src/hooks/index.ts(1 hunks)src/hooks/useAnimations.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/components/Global/Layout/index.tsx
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#845
File: src/components/Request/link/views/Create.request.link.view.tsx:81-81
Timestamp: 2025-05-13T10:05:24.057Z
Learning: In the peanut-ui project, pages that handle request flows (like Create.request.link.view.tsx) are only accessible to logged-in users who will always have a username, making null checks for user?.user.username unnecessary in these contexts.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#669
File: src/lib/validation/recipient.ts:21-56
Timestamp: 2025-02-17T14:07:49.883Z
Learning: In the peanut-ui repository, wrapping switch case blocks in braces to comply with linter rules and avoid variable leakage is considered a non-blocking style improvement.
src/hooks/index.ts (2)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
src/components/LandingPage/index.ts (8)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#484
File: src/components/Cashout/Components/Initial.view.tsx:273-274
Timestamp: 2024-10-25T11:33:46.776Z
Learning: In the `InitialCashoutView` component (`src/components/Cashout/Components/Initial.view.tsx`), linked bank accounts should not generate error states, and the `ValidatedInput` component will clear any error messages if needed. Therefore, it's unnecessary to manually clear the error state when selecting or clearing linked bank accounts.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:141-141
Timestamp: 2024-10-18T01:51:35.247Z
Learning: The `handleConfirm` function in `src/components/Create/Link/Confirm.view.tsx` is separate from the one in `src/components/Offramp/Confirm.view.tsx` and does not need to be renamed when refactoring `handleConfirm` in `src/components/Offramp/Confirm.view.tsx`.
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".
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".
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
src/app/page.tsx (5)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:04.446Z
Learning: Within `src/app/request/pay/page.tsx`, extracting the `getBaseUrl` function does not add significant readability, and the host URL construction code is expected to change soon.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Learnt from: kushagrasarathe
PR: peanutprotocol/peanut-ui#798
File: src/components/Home/HomeHistory.tsx:138-192
Timestamp: 2025-04-11T11:33:53.245Z
Learning: In the HomeHistory component, infinite scrolling is intentionally not implemented despite the presence of useInfiniteQuery and IntersectionObserver code. The component is designed to only display the first 5 entries with a "View all transactions" link for viewing the complete history.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
src/assets/illustrations/index.ts (1)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
src/components/LandingPage/noFees.tsx (10)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Dashboard/useDashboard.tsx:134-134
Timestamp: 2024-10-24T12:36:40.508Z
Learning: In the file `src/components/Dashboard/useDashboard.tsx`, memoization of the `getTokenSymbol` function is not necessary because it is lightweight and does not involve complex computations or network calls.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:96-96
Timestamp: 2024-10-18T08:54:22.142Z
Learning: In the `src/components/Offramp/Confirm.view.tsx` file, it's acceptable to include crass or informal language in code comments.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
src/components/LandingPage/securityBuiltIn.tsx (5)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Request/Create/Views/Initial.view.tsx:81-89
Timestamp: 2024-10-24T12:38:32.793Z
Learning: In `src/components/Request/Create/Views/Initial.view.tsx`, the function `getTokenDetails` is a simple function that does not fetch from the network or perform asynchronous operations.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
src/components/LandingPage/hero.tsx (8)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/components/Create/Create.tsx:108-112
Timestamp: 2025-01-16T13:14:40.363Z
Learning: In the Peanut UI codebase, the `resetTokenContextProvider` function from `tokenSelectorContext` is a stable function reference that doesn't change, so it doesn't need to be included in useEffect dependencies.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#551
File: src/components/Request/Create/Views/Initial.view.tsx:151-156
Timestamp: 2024-12-02T17:19:18.532Z
Learning: In the `InitialView` component at `src/components/Request/Create/Views/Initial.view.tsx`, when setting the default chain and token in the `useEffect` triggered by `isPeanutWallet`, it's acceptable to omit the setters from the dependency array and not include additional error handling for invalid defaults.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#478
File: src/components/Dashboard/useDashboard.tsx:134-134
Timestamp: 2024-10-24T12:36:40.508Z
Learning: In the file `src/components/Dashboard/useDashboard.tsx`, memoization of the `getTokenSymbol` function is not necessary because it is lightweight and does not involve complex computations or network calls.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
Learnt from: jjramirezn
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.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#458
File: src/components/Offramp/Confirm.view.tsx:141-141
Timestamp: 2024-10-18T01:51:35.247Z
Learning: The `handleConfirm` function in `src/components/Create/Link/Confirm.view.tsx` is separate from the one in `src/components/Offramp/Confirm.view.tsx` and does not need to be renamed when refactoring `handleConfirm` in `src/components/Offramp/Confirm.view.tsx`.
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.
src/components/LandingPage/sendInSeconds.tsx (1)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
src/components/LandingPage/yourMoney.tsx (10)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:25:45.170Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(...)` return strings, ensuring that `calculatedFee` consistently returns a string without the need for additional type conversion.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Views/Initial.view.tsx:76-78
Timestamp: 2024-10-07T15:28:25.280Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, both `txFee` and `utils.formatTokenAmount(estimatedGasCost, 3)` return strings, ensuring consistent return types for `calculatedFee`.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#564
File: src/components/Request/Pay/Views/Initial.view.tsx:430-430
Timestamp: 2024-12-11T10:13:22.806Z
Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.
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".
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".
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#469
File: src/app/request/pay/page.tsx:32-64
Timestamp: 2024-10-23T09:38:27.670Z
Learning: In `src/app/request/pay/page.tsx`, if `linkRes` is not OK in the `generateMetadata` function, the desired behavior is to use the standard title and preview image without throwing an error.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-07T15:50:29.173Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#422
File: src/components/Request/Pay/Pay.consts.ts:34-34
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay` components, the `tokenPrice` property in the `IPayScreenProps` interface is only relevant to these views. Other components using `IPayScreenProps` do not need to handle `tokenPriceData` when it's updated in these components.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#535
File: src/components/Claim/Claim.tsx:142-146
Timestamp: 2024-11-18T21:36:11.486Z
Learning: In `src/components/Claim/Claim.tsx`, external calls like token price fetching and cross-chain details retrieval are already encapsulated within existing `try...catch` blocks, so additional error handling may be unnecessary.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#413
File: src/components/Request/Pay/Views/Initial.view.tsx:71-72
Timestamp: 2024-10-08T20:13:42.967Z
Learning: In `src/components/Request/Pay/Views/Initial.view.tsx`, it's acceptable to use the `!` operator in TypeScript to assert that `selectedTokenData` is not `null` or `undefined`, and potential runtime errors from accessing its properties without checks can be disregarded.
src/hooks/useAnimations.ts (5)
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#495
File: src/components/Create/useCreateLink.tsx:647-657
Timestamp: 2024-10-29T16:06:38.812Z
Learning: In the React code for `useCreateLink` in `src/components/Create/useCreateLink.tsx`, the `switchNetwork` function used within `useCallback` hooks is stable and does not need to be included in the dependency arrays.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#857
File: src/hooks/useWebSocket.ts:77-82
Timestamp: 2025-05-15T14:47:26.891Z
Learning: The useWebSocket hook in src/hooks/useWebSocket.ts is designed to provide raw history entries, while the components using it (such as HomeHistory.tsx) are responsible for implementing deduplication logic based on UUID to prevent duplicate entries when combining WebSocket data with other data sources.
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.
Learnt from: jjramirezn
PR: peanutprotocol/peanut-ui#631
File: src/context/kernelClient.context.tsx:88-124
Timestamp: 2025-01-16T13:13:48.615Z
Learning: In React useEffect hooks, when there's an early return condition and async operations, it's correct to have cleanup functions in both the early return and the final return to ensure proper cleanup in all scenarios.
Learnt from: Hugo0
PR: peanutprotocol/peanut-ui#0
File: :0-0
Timestamp: 2025-07-05T16:58:25.340Z
Learning: Hugo0 successfully refactored sessionStorage usage to React Context in the onramp flow, demonstrating preference for centralized state management over browser storage for component-shared state in React applications.
🧬 Code Graph Analysis (1)
src/components/LandingPage/hero.tsx (1)
src/hooks/useAnimations.ts (3)
useResizeHandler(33-60)useScrollHandler(4-31)createButtonAnimation(63-88)
🔇 Additional comments (11)
src/assets/illustrations/index.ts (1)
7-8: LGTM! Asset exports updated correctly.The new
HandTokenexport and updatedAboutPeanutexport path follow the established naming conventions and export patterns in the file.src/hooks/index.ts (1)
1-8: LGTM! Well-structured barrel export.The centralized export pattern provides a clean API for animation hooks and utilities, making them easily accessible across landing page components.
src/components/LandingPage/index.ts (1)
1-8: LGTM! Component exports follow established patterns.The new landing page component exports are consistently structured and follow the existing wildcard export pattern in the file.
src/components/LandingPage/businessIntegrate.tsx (1)
52-60: LGTM! External link properly secured.The external link to the Notion page includes proper security attributes (
noopener noreferrer) and accessibility considerations.src/components/LandingPage/yourMoney.tsx (1)
57-71: LGTM! Responsive image handling implemented correctly.The responsive image switching between mobile and desktop versions using visibility classes is well-implemented with proper Next.js Image optimization.
src/components/LandingPage/noFees.tsx (1)
113-119: Use Next.js Image component for arrow imagesReplace
<Image>tags with proper imports for the arrow SVGs to ensure consistency and enable optimization.First, import the arrow SVGs at the top of the file:
import bottomLeftArrow from '/public/arrows/bottom-left-arrow.svg' import bottomRightArrow from '/public/arrows/bottom-right-arrow.svg'Then update the Image components:
- src="/arrows/bottom-left-arrow.svg" + src={bottomLeftArrow}- src="/arrows/bottom-right-arrow.svg" + src={bottomRightArrow}Also applies to: 123-129
⛔ Skipped due to learnings
Learnt from: jjramirezn PR: peanutprotocol/peanut-ui#564 File: src/components/Request/Pay/Views/Initial.view.tsx:430-430 Timestamp: 2024-12-11T10:13:22.806Z Learning: In the React TypeScript file `src/components/Request/Pay/Views/Initial.view.tsx`, when reviewing the `InitialView` component, do not flag potential issues with using non-null assertion `!` on the `slippagePercentage` variable, as handling undefined values in this context is considered out of scope.src/app/page.tsx (1)
150-158: Well-implemented event handling and cleanupThe scroll and wheel event handling is properly implemented with appropriate cleanup, including restoration of body overflow styles.
src/hooks/useAnimations.ts (4)
63-88: Well-structured animation factory function.The implementation is clean and flexible, providing good customization options while maintaining sensible defaults. The type assertion for
pointerEventsproperly handles TypeScript requirements.
90-112: Good viewport-based animation implementation.The use of
whileInViewis appropriate for scroll-triggered animations. The consistent pattern with other animation factories and sensible defaults make this a solid implementation.
114-127: Mathematically sound cloud animation implementation.The calculation of total distance and animation timing is correct. The fallback for screenWidth aligns with the resize handler's default, and the infinite linear animation is appropriate for cloud movement.
129-146: Excellent accordion animation with good UX considerations.The staggered timing approach (using duration multipliers for different parts) creates a polished user experience. The combination of height, opacity, and icon rotation animations provides comprehensive accordion behavior.
| interface Feature { | ||
| id: number | ||
| title: string | ||
| titleSvg: any | ||
| description: string | ||
| imageSrc: any | ||
| imageAlt: string | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Improve type safety by replacing 'any' types.
The titleSvg and imageSrc properties use any type, which reduces type safety. Consider using more specific types.
interface Feature {
id: number
title: string
- titleSvg: any
+ titleSvg: string
description: string
- imageSrc: any
+ imageSrc: string
imageAlt: string
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/components/LandingPage/yourMoney.tsx around lines 12 to 19, the Feature
interface uses 'any' type for the titleSvg and imageSrc properties, which
reduces type safety. Replace 'any' with more specific types such as
React.ReactNode or React.FC for titleSvg if it represents a React component, and
string or StaticImageData if imageSrc is an image URL or imported image module.
This will improve type safety and clarity.
| interface Feature { | ||
| id: number | ||
| title: string | ||
| titleSvg: any |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use proper types instead of any for SVG imports
Replace any with the actual type for imported SVG modules to improve type safety.
- titleSvg: any
+ titleSvg: { src: string; height: number; width: number; blurDataURL?: string }
description: string
- iconSrc: any
+ iconSrc: { src: string; height: number; width: number; blurDataURL?: string }Also applies to: 17-17
🤖 Prompt for AI Agents
In src/components/LandingPage/securityBuiltIn.tsx at lines 15 and 17, replace
the type annotation 'any' used for SVG imports with the appropriate type for SVG
modules, such as React.FunctionComponent<React.SVGProps<SVGSVGElement>> or a
similar SVG-specific type, to enhance type safety and maintain proper typing for
SVG components.
| variant === 'primary' && ( | ||
| <> | ||
| <Image | ||
| src="/arrows/small-arrow.svg" |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Import arrow SVGs instead of using hardcoded paths
Similar to the previous file, use proper imports for arrow SVGs.
Add import at the top:
import smallArrow from '/public/arrows/small-arrow.svg'Then update all Image src props:
- src="/arrows/small-arrow.svg"
+ src={smallArrow}Also applies to: 48-48, 53-53, 56-56, 61-61, 64-64, 70-70, 73-73
🤖 Prompt for AI Agents
In src/components/LandingPage/hero.tsx around lines 45, 48, 53, 56, 61, 64, 70,
and 73, the arrow SVGs are currently referenced using hardcoded string paths in
the src attribute. Replace these string paths by importing the SVG files at the
top of the file using import statements (e.g., import smallArrow from
'/public/arrows/small-arrow.svg') and then update the Image components to use
these imported variables as the src prop values.
| const renderArrows = () => ( | ||
| <> | ||
| <Image | ||
| src="/arrows/small-arrow.svg" |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Import arrow SVGs for consistency
Use proper imports for arrow SVGs as suggested in other components.
import smallArrow from '/public/arrows/small-arrow.svg'Then update Image src props throughout the component.
Also applies to: 47-47, 54-54, 61-61
🤖 Prompt for AI Agents
In src/components/LandingPage/sendInSeconds.tsx at lines 40, 47, 54, and 61, the
arrow SVGs are used via string paths in the src attribute. To maintain
consistency with other components, import the SVG files at the top of the file
using ES module imports like "import smallArrow from
'/public/arrows/small-arrow.svg'". Then replace the src string props in the
Image components with the imported variables to properly reference the SVGs.
| const stickyButtonTop = window.innerHeight - 16 - 52 // 16px bottom margin, ~52px button height | ||
| const stickyButtonBottom = window.innerHeight - 16 |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Extract magic numbers as named constants
The hardcoded values make the code harder to understand and maintain. Extract them as descriptive constants.
Add these constants at the component level:
const STICKY_BUTTON_HEIGHT = 52
const STICKY_BUTTON_MARGIN = 16
const FREEZE_OVERLAP_OFFSET = 60
const SCROLL_THRESHOLD = 50
const SHRINK_DISTANCE = 200
const MAX_VIRTUAL_SCROLL = 500
const MAX_BUTTON_SCALE = 1.5Then use them throughout the code:
- const stickyButtonTop = window.innerHeight - 16 - 52
+ const stickyButtonTop = window.innerHeight - STICKY_BUTTON_MARGIN - STICKY_BUTTON_HEIGHTAlso applies to: 86-88, 134-135
🤖 Prompt for AI Agents
In src/app/page.tsx around lines 81-82, 86-88, and 134-135, there are multiple
hardcoded numeric values used directly in calculations, which reduces code
clarity and maintainability. Define the provided constants
(STICKY_BUTTON_HEIGHT, STICKY_BUTTON_MARGIN, FREEZE_OVERLAP_OFFSET,
SCROLL_THRESHOLD, SHRINK_DISTANCE, MAX_VIRTUAL_SCROLL, MAX_BUTTON_SCALE) at the
component level and replace all corresponding magic numbers in these lines with
the appropriate named constants to improve readability and ease future updates.
| export function useScrollHandler(throttleMs = 16) { | ||
| const [scrollY, setScrollY] = useState(0) | ||
|
|
||
| useEffect(() => { | ||
| let timeoutId: NodeJS.Timeout | null = null | ||
|
|
||
| const handleScroll = () => { | ||
| if (timeoutId) return | ||
|
|
||
| timeoutId = setTimeout(() => { | ||
| setScrollY(window.scrollY) | ||
| timeoutId = null | ||
| }, throttleMs) | ||
| } | ||
|
|
||
| handleScroll() | ||
| window.addEventListener('scroll', handleScroll) | ||
|
|
||
| return () => { | ||
| window.removeEventListener('scroll', handleScroll) | ||
| if (timeoutId) { | ||
| clearTimeout(timeoutId) | ||
| } | ||
| } | ||
| }, [throttleMs]) | ||
|
|
||
| return scrollY | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add SSR safety checks and consider throttling improvements.
The hook has good throttling logic but could benefit from SSR safety improvements:
- Add a check for
windowavailability to prevent SSR issues - Consider if the throttling should guarantee the last scroll event is processed
export function useScrollHandler(throttleMs = 16) {
const [scrollY, setScrollY] = useState(0)
useEffect(() => {
+ if (typeof window === 'undefined') return
+
let timeoutId: NodeJS.Timeout | null = null
const handleScroll = () => {
if (timeoutId) return
timeoutId = setTimeout(() => {
setScrollY(window.scrollY)
timeoutId = null
}, throttleMs)
}
handleScroll()
window.addEventListener('scroll', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
if (timeoutId) {
clearTimeout(timeoutId)
}
}
}, [throttleMs])
return scrollY
}📝 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.
| export function useScrollHandler(throttleMs = 16) { | |
| const [scrollY, setScrollY] = useState(0) | |
| useEffect(() => { | |
| let timeoutId: NodeJS.Timeout | null = null | |
| const handleScroll = () => { | |
| if (timeoutId) return | |
| timeoutId = setTimeout(() => { | |
| setScrollY(window.scrollY) | |
| timeoutId = null | |
| }, throttleMs) | |
| } | |
| handleScroll() | |
| window.addEventListener('scroll', handleScroll) | |
| return () => { | |
| window.removeEventListener('scroll', handleScroll) | |
| if (timeoutId) { | |
| clearTimeout(timeoutId) | |
| } | |
| } | |
| }, [throttleMs]) | |
| return scrollY | |
| } | |
| export function useScrollHandler(throttleMs = 16) { | |
| const [scrollY, setScrollY] = useState(0) | |
| useEffect(() => { | |
| if (typeof window === 'undefined') return | |
| let timeoutId: NodeJS.Timeout | null = null | |
| const handleScroll = () => { | |
| if (timeoutId) return | |
| timeoutId = setTimeout(() => { | |
| setScrollY(window.scrollY) | |
| timeoutId = null | |
| }, throttleMs) | |
| } | |
| handleScroll() | |
| window.addEventListener('scroll', handleScroll) | |
| return () => { | |
| window.removeEventListener('scroll', handleScroll) | |
| if (timeoutId) { | |
| clearTimeout(timeoutId) | |
| } | |
| } | |
| }, [throttleMs]) | |
| return scrollY | |
| } |
🤖 Prompt for AI Agents
In src/hooks/useAnimations.ts around lines 4 to 31, the useScrollHandler hook
lacks server-side rendering (SSR) safety checks and may miss processing the last
scroll event due to throttling. Add a check to ensure window is defined before
accessing window.scrollY or adding event listeners to avoid SSR errors. Also,
modify the throttling logic to guarantee the last scroll event is handled, for
example by using a trailing invocation or a more robust throttling/debouncing
approach.
| export function useResizeHandler(throttleMs = 16) { | ||
| const [screenWidth, setScreenWidth] = useState(1080) | ||
|
|
||
| useEffect(() => { | ||
| let timeoutId: NodeJS.Timeout | null = null | ||
|
|
||
| const handleResize = () => { | ||
| if (timeoutId) return | ||
|
|
||
| timeoutId = setTimeout(() => { | ||
| setScreenWidth(window.innerWidth) | ||
| timeoutId = null | ||
| }, throttleMs) | ||
| } | ||
|
|
||
| handleResize() | ||
| window.addEventListener('resize', handleResize) | ||
|
|
||
| return () => { | ||
| window.removeEventListener('resize', handleResize) | ||
| if (timeoutId) { | ||
| clearTimeout(timeoutId) | ||
| } | ||
| } | ||
| }, [throttleMs]) | ||
|
|
||
| return screenWidth | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add SSR safety and consider default screen width.
Similar to useScrollHandler, this hook needs SSR safety improvements. Also consider if 1080px is an appropriate default screen width for all use cases.
export function useResizeHandler(throttleMs = 16) {
- const [screenWidth, setScreenWidth] = useState(1080)
+ const [screenWidth, setScreenWidth] = useState(typeof window !== 'undefined' ? window.innerWidth : 1080)
useEffect(() => {
+ if (typeof window === 'undefined') return
+
let timeoutId: NodeJS.Timeout | null = null
const handleResize = () => {
if (timeoutId) return
timeoutId = setTimeout(() => {
setScreenWidth(window.innerWidth)
timeoutId = null
}, throttleMs)
}
handleResize()
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
if (timeoutId) {
clearTimeout(timeoutId)
}
}
}, [throttleMs])
return screenWidth
}🤖 Prompt for AI Agents
In src/hooks/useAnimations.ts around lines 33 to 60, the useResizeHandler hook
lacks server-side rendering (SSR) safety and uses a fixed default screen width
of 1080px which may not suit all cases. To fix this, add a check to ensure
window is defined before accessing window.innerWidth to avoid errors during SSR.
Also, consider making the default screen width configurable or set it to a more
neutral value like 0 or undefined to better accommodate different environments.
6ce5a92 to
e2ace5f
Compare
Signed-off-by: facundobozzi <72771544+FacuBozzi@users.noreply.github.com>
Signed-off-by: facundobozzi <72771544+FacuBozzi@users.noreply.github.com>
Addressed Hugo Notes
Except the CodeRabbit suggestions one
Also addressed Manu's notes