Skip to content

Feat/new landing page#991

Open
FacuBozzi wants to merge 87 commits intodevfrom
feat/new-landing-page
Open

Feat/new landing page#991
FacuBozzi wants to merge 87 commits intodevfrom
feat/new-landing-page

Conversation

@FacuBozzi
Copy link
Contributor

Addressed Hugo Notes

9k LoC json file incorrectly added to diff (should be moved back to where it was)
new index.ts TOPLEVEL file is incorrect
should not hardcode colors
there's a lot of repetitive code for anim handling

Except the CodeRabbit suggestions one

Also addressed Manu's notes

@vercel
Copy link

vercel bot commented Jul 16, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
peanut-wallet ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jul 17, 2025 0:21am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 16, 2025

Walkthrough

This 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

File(s) Change Summary
src/app/page.tsx Expanded landing page with new content sections, multiple marquees, and a complex scroll/wheel-driven sticky button animation controlling the SendInSeconds component. Adjusted Hero and FAQ usage.
src/components/LandingPage/businessIntegrate.tsx, src/components/LandingPage/noFees.tsx, src/components/LandingPage/sendInSeconds.tsx, src/components/LandingPage/securityBuiltIn.tsx, src/components/LandingPage/yourMoney.tsx Added new visually rich React components for BusinessIntegrate, NoFees, SendInSeconds, SecurityBuiltIn, and YourMoney landing page sections, each with animations, illustrations, headings, and call-to-action elements.
src/components/LandingPage/hero.tsx Refactored Hero component to use centralized animation hooks; replaced inline animation with createButtonAnimation; removed marquee and secondary CTA props; adjusted button rendering and layout; updated images and removed unused imports.
src/components/LandingPage/index.ts Added exports for new landing page section components (businessIntegrate, noFees, securityBuiltIn, sendInSeconds, yourMoney).
src/hooks/useAnimations.ts, src/hooks/index.ts Introduced new hooks and animation utility functions for scroll/resize event handling and reusable animation configs; index file re-exports all animation-related hooks and utilities for centralized imports.

Possibly related PRs

  • [TASK-12771] Feat/new landing page #974: Directly related; both PRs modify the landing page to add new components and implement the same scroll-driven sticky button animation for the SendInSeconds component.

Suggested reviewers

  • Hugo0

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ce5a92 and e2ace5f.

📒 Files selected for processing (5)
  • src/components/LandingPage/hero.tsx (4 hunks)
  • src/components/LandingPage/noFees.tsx (1 hunks)
  • src/components/LandingPage/sendInSeconds.tsx (1 hunks)
  • src/hooks/index.ts (1 hunks)
  • src/hooks/useAnimations.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/hooks/index.ts
  • src/components/LandingPage/hero.tsx
  • src/components/LandingPage/sendInSeconds.tsx
  • src/components/LandingPage/noFees.tsx
  • src/hooks/useAnimations.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/new-landing-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai bot added the enhancement New feature or request label Jul 16, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 like font-light for 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: 500 and letterSpacing: '-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 redundant text-left class

The parent div already handles text alignment with text-center md:text-left, making this text-left class 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 consistency

Consider 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 unused renderSparkle function

The renderSparkle function is defined but never used (commented out at line 109). Remove it to reduce code clutter.

Remove the entire renderSparkle function (lines 32-40) since it's not being used.

Also applies to: 109-109


98-98: Remove unused arrowOpacity variable

The arrowOpacity variable is always set to 1. Remove it and use the value directly.

-        const arrowOpacity = 1 // Always visible
         const animation = variant === 'primary' ? primaryButtonAnimation : secondaryButtonAnimation

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

The hardcoded value 1740 is 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 useMemo import 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

📥 Commits

Reviewing files that changed from the base of the PR and between 66f0d03 and ddb42e9.

⛔ Files ignored due to path filters (31)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/arrows/small-arrow.svg is excluded by !**/*.svg
  • src/assets/illustrations/biometric-protection.svg is excluded by !**/*.svg
  • src/assets/illustrations/border-cloud.svg is excluded by !**/*.svg
  • src/assets/illustrations/exclamations.svg is excluded by !**/*.svg
  • src/assets/illustrations/free-global-transfers.svg is excluded by !**/*.svg
  • src/assets/illustrations/get-paid-worldwide.svg is excluded by !**/*.svg
  • src/assets/illustrations/got-it-hand-flipped.svg is excluded by !**/*.svg
  • src/assets/illustrations/got-it-hand.svg is excluded by !**/*.svg
  • src/assets/illustrations/hand-peace.svg is excluded by !**/*.svg
  • src/assets/illustrations/hand-waving.svg is excluded by !**/*.svg
  • src/assets/illustrations/instantly-send-receive.svg is excluded by !**/*.svg
  • src/assets/illustrations/kyc-only-when-required.svg is excluded by !**/*.svg
  • src/assets/illustrations/mobile-security-privacy-built-in.svg is excluded by !**/*.svg
  • src/assets/illustrations/mobile-send-in-seconds.svg is excluded by !**/*.svg
  • src/assets/illustrations/mobile-your-money-anywhere.svg is excluded by !**/*.svg
  • src/assets/illustrations/mobile-zero-fees.svg is excluded by !**/*.svg
  • src/assets/illustrations/new-hand-token.svg is excluded by !**/*.svg
  • src/assets/illustrations/new-hero-description.svg is excluded by !**/*.svg
  • src/assets/illustrations/no-hidden-fees.svg is excluded by !**/*.svg
  • src/assets/illustrations/pay-anyone-anywhere.svg is excluded by !**/*.svg
  • src/assets/illustrations/pay-zero-fees.svg is excluded by !**/*.svg
  • src/assets/illustrations/peanut-means.svg is excluded by !**/*.svg
  • src/assets/illustrations/security-privacy-built-in.svg is excluded by !**/*.svg
  • src/assets/illustrations/self-custodial-design.svg is excluded by !**/*.svg
  • src/assets/illustrations/your-money-anywhere.svg is excluded by !**/*.svg
  • src/assets/illustrations/zero.svg is excluded by !**/*.svg
  • src/assets/iphone-ss/iphone-your-money-1.png is excluded by !**/*.png
  • src/assets/iphone-ss/iphone-your-money-2.png is excluded by !**/*.png
  • src/assets/iphone-ss/iphone-your-money-3.png is excluded by !**/*.png
  • src/assets/scribble.svg is 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 HandToken export and updated AboutPeanut export 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 images

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

The 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 pointerEvents properly handles TypeScript requirements.


90-112: Good viewport-based animation implementation.

The use of whileInView is 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.

Comment on lines +12 to +19
interface Feature {
id: number
title: string
titleSvg: any
description: string
imageSrc: any
imageAlt: string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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.

Comment on lines +81 to +82
const stickyButtonTop = window.innerHeight - 16 - 52 // 16px bottom margin, ~52px button height
const stickyButtonBottom = window.innerHeight - 16
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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.5

Then use them throughout the code:

-                const stickyButtonTop = window.innerHeight - 16 - 52
+                const stickyButtonTop = window.innerHeight - STICKY_BUTTON_MARGIN - STICKY_BUTTON_HEIGHT

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

Comment on lines +4 to +31
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
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add SSR safety checks and consider throttling improvements.

The hook has good throttling logic but could benefit from SSR safety improvements:

  1. Add a check for window availability to prevent SSR issues
  2. 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.

Suggested change
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.

Comment on lines +33 to +60
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
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ 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.

@FacuBozzi FacuBozzi force-pushed the feat/new-landing-page branch from 6ce5a92 to e2ace5f Compare July 16, 2025 21:18
Signed-off-by: facundobozzi <72771544+FacuBozzi@users.noreply.github.com>
Signed-off-by: facundobozzi <72771544+FacuBozzi@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant