Skip to content

Index redesign#1719

Merged
simo6529 merged 47 commits intomainfrom
index-redesign
Jan 16, 2026
Merged

Index redesign#1719
simo6529 merged 47 commits intomainfrom
index-redesign

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Jan 8, 2026

Summary by CodeRabbit

  • New Features

    • Rich homepage: submission carousel, Now Minting (artwork, details, countdowns), Boosted Drops, Explore Waves, Next‑Mint & Leading highlights, hero/header, carousel arrows/cards, and vote panel.
  • Improvements

    • Adaptive & verbose countdowns, optional media autoplay/modal controls, improved carousel navigation, loading/empty states and UI polish.
  • Refactor

    • Homepage rendering simplified; leaderboard hooks/components no longer require auth-derived parameters.
  • Documentation

    • Specs for carousel, Now Minting, Explore Waves, and homepage sections.
  • Tests

    • Added media modal and video autoplay tests.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

Extracted server-side Home rendering into a client HomePageContent and removed server-side data fetching; added carousel, now‑minting, boosted, and explore‑waves UI and hooks; tightened media autoplay/modal controls; made IPFS URL resolver synchronous; removed AuthContext from leaderboard hooks and threaded onDropClick routing through sidebar and leaderboard components.

Changes

Cohort / File(s) Summary
Home entry & composition
app/page.tsx, components/home/HomePageContent.tsx
Replace async server Page with a synchronous Page and extract client HomePageContent; remove server-side fetches and make generateMetadata synchronous.
Carousel / submissions
components/home/carousel/*, styles/swiper.scss
Add SubmissionCarousel, SubmissionArtworkCard, CarouselArrow, CarouselActiveItemVote, CarouselActiveItemDetails and scoped swiper CSS; active-drop propagation and navigation controls.
Now‑minting UI & hooks
components/home/now-minting/*, hooks/useMintCountdownState.ts, hooks/useNowMinting.ts, components/react-query-wrapper/ReactQueryWrapper.tsx
New NowMinting component suite (Artwork, Header, StatsGrid, DetailsAccordion, Countdown variants), new useMintCountdownState and useNowMinting hooks, and add QueryKey.MEMES_LATEST.
Boosted & next‑mint sections
components/home/boosted/*, components/home/next-mint-leading/*, components/home/boosted/index.ts
Add BoostedSection, BoostedDropCardHome, NextMintLeadingSection, NextMintCard, LeadingCard; horizontal scroller and re-exports.
Explore waves
components/home/explore-waves/*
Add ExploreWavesSection, ExploreWaveCard, ExploreWaveCardSkeleton, useWaveLatestDrop, extractDropPreview, and index re-exports.
Hook refactors & countdowns
hooks/useWaveDropsLeaderboard.ts, hooks/waves/useWaveDecisions.ts, hooks/useCountdown.ts, utils/timeFormatters.ts, hooks/useBoostedDrops.ts
Remove connectedProfileHandle from leaderboard hook; switch useWaveDecisions to accept waveId; refactor useCountdown and add useCountdownAdaptive/useCountdownVerbose; add formatCountdownAdaptive/formatCountdownVerbose; add useBoostedDrops.
AuthContext removal & drop‑click plumbing
components/brain/*, components/waves/*, components/brain/right-sidebar/WaveContent.tsx, components/shared/WavesMessagesWrapper.tsx
Remove AuthContext usage; add onDropClick prop across small leaderboards/winners; implement client routing (useRouter/useSearchParams) to set drop query param and push without scroll; wire callbacks through sidebar.
Media components: modal / autoplay control
components/drops/view/item/content/media/*, __tests__/**
Add props disableModal, disableAutoPlay, imageObjectPosition; gate modal/autoplay/HTML activation; add tests validating new behaviors.
Leaderboard / winners refinements
components/waves/small-leaderboard/*, components/waves/winners/*, components/waves/leaderboard/sidebar/*
Improve null-safety and rank checks (typeof number), fallback author handle → primary_address, icon sizing utility updates, and minor UI/class adjustments.
IPFS & utilities
components/ipfs/IPFSContext.tsx, utils/timeFormatters.ts
Make resolveIpfsUrl synchronous (use resolveIpfsUrlSync); add formatCountdownAdaptive and formatCountdownVerbose.
Tests, docs & misc
__tests__/**, docs/**, tsconfig.json, styles, small components
Add/adjust tests; extensive docs for carousel/now‑minting/explore‑waves/effects; extend tsconfig excludes; assorted style and small component updates.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant Carousel as SubmissionCarousel
  participant Home as HomePageContent
  participant Sidebar as WaveContent
  participant Search as URLSearchParams
  participant Router as NextRouter

  User->>Carousel: click/swipe/select slide
  Carousel->>Home: onActiveDropChange(drop)
  Home->>Sidebar: call onDropClick(drop)
  Sidebar->>Search: params.set("drop", drop.serial_no)
  Sidebar->>Router: router.push(pathname + "?" + params.toString(), { scroll: false })
  Router-->>User: navigation updated (sidebar/drop overlay)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • analyticsflowee

Poem

🐰
I hopped through modules with a twitchy nose,
Spun carousels and countdowns in tidy little rows.
Boosted drops parade, previews softly sing,
A click nests in params — the router does its thing.
Home blooms client-side; I nibble code and doze.

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Index redesign' is vague and does not clearly convey the scope of changes. The PR encompasses a comprehensive homepage redesign with multiple new sections (carousel, now-minting, boosted drops, explore waves, next-mint-leading), hook refactors, and significant component restructuring. Use a more descriptive title that reflects the main changes, such as 'Redesign homepage with new carousel and sections' or 'Refactor home page layout with carousel, minting, and discovery sections'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
components/home/carousel/SubmissionArtworkCard.tsx (1)

49-55: Reuse the extracted media variable instead of re-accessing with non-null assertions.

The media variable is already extracted at line 21 and validated at line 32. Re-accessing drop.parts[0]?.media[0]! is redundant and the non-null assertion on url could mask a runtime error if url is undefined.

Suggested fix
         <MediaDisplay
-          media_mime_type={drop.parts[0]?.media[0]!.mime_type ?? "image/jpeg"}
-          media_url={drop.parts[0]?.media[0]!.url!}
+          media_mime_type={media.mime_type ?? "image/jpeg"}
+          media_url={media.url ?? ""}
           disableMediaInteraction={true}
           imageScale={mediaImageScale}
           previewImageUrl={previewImageUrl}
         />

If media.url can be undefined, consider adding an explicit check alongside the existing media check:

- if (!media) {
+ if (!media?.url) {
     return null;
   }

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f4bb07 and 009671a.

📒 Files selected for processing (5)
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/hero/CarouselHeader.tsx
  • components/home/hero/HeroHeader.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/hero/CarouselHeader.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
components/home/carousel/SubmissionArtworkCard.tsx (3)
helpers/waves/drop.helpers.ts (2)
  • ExtendedDrop (19-23)
  • getDropPreviewImageUrl (168-185)
hooks/useMediaQuery.ts (1)
  • useMediaQuery (3-18)
components/drops/view/item/content/media/MediaDisplay.tsx (1)
  • MediaDisplay (32-114)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
components/home/hero/HeroHeader.tsx (1)

1-12: Clean, minimal hero header component.
Structure and semantics look good for a static header.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 3

🤖 Fix all issues with AI agents
In @components/home/carousel/CarouselActiveItemDetails.tsx:
- Around line 75-81: In CarouselActiveItemDetails, remove the inline <svg> star
element and replace it with the FontAwesome star icon: import { FontAwesomeIcon
} from '@fortawesome/react-fontawesome' and import { faStar } from
'@fortawesome/free-solid-svg-icons' at the top of the file, then render
<FontAwesomeIcon icon={faStar} className="tw-size-4 tw-text-yellow-500" /> in
place of the SVG so styling and semantics match the original.

In @components/home/carousel/CarouselArrow.tsx:
- Around line 25-37: In CarouselArrow, remove the inline <svg> block and render
a FontAwesome icon instead: import FontAwesomeIcon from
'@fortawesome/react-fontawesome' and the faChevronLeft icon from
'@fortawesome/free-solid-svg-icons', then replace the SVG with <FontAwesomeIcon
icon={faChevronLeft} /> keeping the existing className/rotation logic driven by
the isLeft prop (e.g., apply `tw-size-5` and conditionally `tw-rotate-180` based
on isLeft) and preserve accessibility attributes and styling already used by the
component.

In @components/waves/small-leaderboard/WaveSmallLeaderboard.tsx:
- Around line 26-30: The callback passed to useIntersectionObserver is currently
async which is ignored by the hook; remove the async keyword and do not await
inside the callback—instead call fetchNextPage() and handle its promise outside
(e.g., trigger a state flag and run an effect that awaits fetchNextPage), or
move the async logic into a useEffect in the parent component that watches the
intersectionElementRef/flag; update the intersectionElementRef callback to a
synchronous (state: boolean) => void and ensure fetchNextPage is
awaited/try-catched in that separate effect so unhandled promise rejections are
avoided.
🧹 Nitpick comments (5)
components/home/carousel/CarouselActiveItemDetails.tsx (1)

41-46: Vote button has no functionality.

The Vote button renders without an onClick handler or any interactive behavior. If this is a placeholder for future implementation, consider adding a TODO comment or disabling the button.

Suggested approaches

Option 1: Add a disabled state if not yet implemented:

       <button
         type="button"
+        disabled
-        className="tw-rounded-lg tw-border tw-border-iron-700 tw-bg-transparent tw-px-5 tw-py-1.5 tw-text-sm tw-font-medium tw-text-white tw-transition-colors tw-duration-200 hover:tw-border-iron-600 hover:tw-bg-iron-800"
+        className="tw-rounded-lg tw-border tw-border-iron-700 tw-bg-transparent tw-px-5 tw-py-1.5 tw-text-sm tw-font-medium tw-text-white tw-transition-colors tw-duration-200 hover:tw-border-iron-600 hover:tw-bg-iron-800 disabled:tw-cursor-not-allowed disabled:tw-opacity-50"
       >

Option 2: Accept an onVote prop:

 interface CarouselActiveItemDetailsProps {
   readonly drop: ExtendedDrop | null;
+  readonly onVote?: (drop: ExtendedDrop) => void;
 }
 
 export default function CarouselActiveItemDetails({
   drop,
+  onVote,
 }: CarouselActiveItemDetailsProps) {
   ...
       <button
         type="button"
+        onClick={() => onVote?.(drop)}
+        disabled={!onVote}
         className="..."
docs/home-page-spec.md (1)

9-14: Add language specifiers to fenced code blocks for better markdown compliance.

The ASCII art diagrams in fenced code blocks should specify a language identifier (e.g., text) to comply with markdown linting rules and improve rendering consistency across different markdown viewers.

📝 Proposed fix

For each fenced code block, add text as the language identifier:

-```
+```text
          ┌─────────┐ ┌─────────┐ ┌─────────┐
     ◀    │         │ │  MAIN   │ │         │    ▶
          │  prev   │ │ ARTWORK │ │  next   │
          └─────────┘ └─────────┘ └─────────┘

Apply the same change to the other three code blocks at lines 20, 31, and 43.

Also applies to: 20-25, 31-37, 43-49

components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (1)

28-28: Optional: Remove unnecessary await keyword.

The result of fetchNextPage() is not used, so the await keyword is unnecessary. While not harmful, removing it would make the code slightly cleaner.

♻️ Proposed refactor
-      await fetchNextPage();
+      fetchNextPage();
components/home/carousel/SubmissionCarousel.tsx (2)

29-40: Shuffle produces non-deterministic results on each data refetch.

The Fisher-Yates shuffle uses Math.random() within a useMemo, which means the order will change whenever the drops dependency updates (e.g., from polling or refetching). While the shuffle implementation is correct, this could create a jarring UX where items suddenly reorder.

Consider seeding the random number generator or using a stable shuffle key if consistent ordering between refetches is desired.

♻️ Optional: Stable shuffle using drop IDs as seed
  const shuffledDrops = useMemo(() => {
    const filtered = drops.filter(
      (drop) => (drop.parts[0]?.media.length ?? 0) > 0
    );
-    // Fisher-Yates shuffle
+    
+    // Create a seed from drop IDs for consistent shuffle
+    const seed = filtered.map(d => d.id).join('').split('').reduce((a, b) => {
+      a = ((a << 5) - a) + b.charCodeAt(0);
+      return a & a;
+    }, 0);
+    
+    // Seeded random function
+    let currentSeed = Math.abs(seed);
+    const seededRandom = () => {
+      currentSeed = (currentSeed * 9301 + 49297) % 233280;
+      return currentSeed / 233280;
+    };
+    
     const shuffled = [...filtered];
     for (let i = shuffled.length - 1; i > 0; i--) {
-      const j = Math.floor(Math.random() * (i + 1));
+      const j = Math.floor(seededRandom() * (i + 1));
       [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
     }
     return shuffled;
   }, [drops]);

167-184: Consider adding ARIA attributes for carousel accessibility.

The carousel implementation lacks ARIA attributes that would help screen readers understand the carousel structure. Consider adding role="region", aria-label, aria-live for the active item, and aria-current for the active card.

♻️ Accessibility improvements
  <button
    type="button"
    key={drop.id}
    data-carousel-item
    onClick={() => scrollToIndex(index)}
+   aria-label={`Submission ${index + 1} of ${shuffledDrops.length}${isActive ? ', currently active' : ''}`}
+   aria-current={isActive ? "true" : undefined}
    className="tw-flex-shrink-0 tw-rounded-xl tw-border-none tw-bg-transparent tw-p-0 tw-outline-none focus-visible:tw-ring-2 focus-visible:tw-ring-primary-400"
    style={{
      width: "350px",
      transform: `scale(${isActive ? 1 : 0.85})`,
      opacity: isActive ? 1 : 0.4,
      filter: isActive ? "none" : "grayscale(50%)",
      zIndex: isActive ? 10 : 10 - distance,
      transition:
        "transform 0.4s cubic-bezier(0.33, 1, 0.68, 1), opacity 0.4s cubic-bezier(0.33, 1, 0.68, 1), filter 0.4s cubic-bezier(0.33, 1, 0.68, 1)",
    }}
  >
    <SubmissionArtworkCard drop={drop} />
  </button>

And wrap the carousel track:

+ <div role="region" aria-label="Submission carousel" aria-live="polite">
    <div
      ref={trackRef}
      className="tw-flex tw-items-center tw-overflow-x-auto tw-scroll-smooth tw-scrollbar-none"
      ...
    >
      {/* cards */}
    </div>
+ </div>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 50d61c6 and 027fffe.

📒 Files selected for processing (15)
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • app/page.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/home/HomePageContent.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • docs/home-page-spec.md
  • hooks/useWaveDropsLeaderboard.ts
  • styles/Home.module.scss
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • hooks/useWaveDropsLeaderboard.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • app/page.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
app/**/+(layout|page|route|error|loading|not-found|default).{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Routes in app/ should export generateMetadata using the helper function getAppMetadata from @/components/providers/metadata with proper typing from 'next' package.

Files:

  • app/page.tsx
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

app/**/*.{ts,tsx}: Prefer Server Components with inline fetches for data reads; use Server Functions/Server Actions ('use server') for mutations
Use 'use cache' directive at the top of Server Components, routes, or functions to opt-in caching (Next.js 16+)

Files:

  • app/page.tsx
app/**/page.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Routes should export generateMetadata using the getAppMetadata helper for proper metadata

Files:

  • app/page.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run test to execute all Jest tests and enforce ≥80% line coverage for files changed since main. Tests must pass and coverage threshold must be met before completing any task.

Enforce ≥ 80% line coverage for files changed since main by running npm run test

Files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/{__tests__,*.test.{tsx,ts}}

📄 CodeRabbit inference engine (AGENTS.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside the component

Files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
**/*.{test,spec}.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
🧠 Learnings (18)
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • hooks/useWaveDropsLeaderboard.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Fix issues with modernization aligned to React 19.2, React Compiler, and Next.js 16 conventions. Do not add `// eslint-disable` comments unless explicitly instructed.

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Prefer direct named imports from React (`useMemo`, `useRef`, `FC`) over `React.` namespace usage

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to app/**/page.{ts,tsx} : Routes should export `generateMetadata` using the `getAppMetadata` helper for proper metadata

Applied to files:

  • app/page.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to app/**/*.{ts,tsx} : Prefer Server Components with inline fetches for data reads; use Server Functions/Server Actions (`'use server'`) for mutations

Applied to files:

  • app/page.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Move data fetching from client Effects to Server Components; mutations go through Server Actions (`'use server'`)

Applied to files:

  • app/page.tsx
  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Applied to files:

  • components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{test,spec}.{tsx,ts} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/__tests__/**/*.{test,spec}.{ts,tsx,js,jsx}|**/*.{test,spec}.{ts,tsx,js,jsx} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` files. Mock external dependencies and APIs in tests.

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Use `globalThis.fetch()` instead of direct `fetch()` calls

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Use realistic production-like data in tests

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Follow Arrange – Act – Assert pattern in test structure

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__mocks__/**/*.{ts,tsx,js} : Jest automatically picks up mocks from `__mocks__` directory

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.test.ts
  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Avoid double negatives in code; prefer explicit statements and use optional chaining (`?.`)

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Limit function cognitive complexity to 15 or less; extract deep ternaries (>3 levels)

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Write one behaviour per test with clear, descriptive test names

Applied to files:

  • __tests__/hooks/useWaveDropsLeaderboard.extra.test.ts
🧬 Code graph analysis (8)
components/home/carousel/CarouselActiveItemDetails.tsx (4)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
helpers/Helpers.ts (1)
  • numberWithCommas (114-131)
components/user/utils/level/UserLevel.tsx (1)
  • UserLevel (9-54)
components/utils/CommonTimeAgo.tsx (1)
  • CommonTimeAgo (5-40)
components/home/carousel/SubmissionArtworkCard.tsx (2)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-95)
app/page.tsx (1)
components/home/HomePageContent.tsx (1)
  • HomePageContent (5-11)
components/home/carousel/SubmissionCarousel.tsx (5)
contexts/SeizeSettingsContext.tsx (1)
  • useSeizeSettings (119-127)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (62-314)
components/home/carousel/CarouselArrow.tsx (1)
  • CarouselArrow (9-40)
components/home/carousel/SubmissionArtworkCard.tsx (1)
  • SubmissionArtworkCard (12-36)
components/home/carousel/CarouselActiveItemDetails.tsx (1)
  • CarouselActiveItemDetails (13-97)
components/home/HomePageContent.tsx (1)
components/home/carousel/SubmissionCarousel.tsx (1)
  • SubmissionCarousel (13-200)
components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx (1)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (62-314)
__tests__/hooks/useWaveDropsLeaderboard.test.ts (1)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (62-314)
__tests__/hooks/useWaveDropsLeaderboard.extra.test.ts (1)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (62-314)
🪛 markdownlint-cli2 (0.18.1)
docs/home-page-spec.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


20-20: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


43-43: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (19)
styles/Home.module.scss (1)

165-170: LGTM - Improved readability.

The multi-line formatting of the box-shadow property enhances readability without changing functionality.

components/brain/my-stream/votes/MyStreamWaveMyVotes.tsx (2)

84-86: LGTM - Proper apostrophe escaping.

The use of &apos; for the apostrophe in "haven't" is correct for JSX/HTML entities.


71-75: Fix type error: remove async/await from intersection observer callback.

The useIntersectionObserver hook expects a synchronous callback with signature (state: boolean) => void, but the code passes an async function. Since async functions return Promise<void> (not void), this breaks the type contract and causes the promise to be ignored at runtime. Remove the async/await from the callback—the hook doesn't support async callbacks and the IntersectionObserver API requires synchronous execution.

⛔ Skipped due to learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Fix issues with modernization aligned to React 19.2, React Compiler, and Next.js 16 conventions. Do not add `// eslint-disable` comments unless explicitly instructed.
components/home/carousel/CarouselActiveItemDetails.tsx (1)

61-70: LGTM - Proper conditional rendering.

The use of !!drop.created_at ensures the timestamp section only renders when a valid creation date exists.

components/home/carousel/SubmissionArtworkCard.tsx (1)

12-36: LGTM - Clean implementation.

The component properly handles edge cases with optional chaining and null checks, uses appropriate image scaling, and follows React 19 functional component patterns with readonly props.

components/home/HomePageContent.tsx (1)

1-11: LGTM! Clean and appropriate component structure.

The component correctly uses the "use client" directive and provides a simple, focused wrapper for the SubmissionCarousel. The separation of concerns is appropriate, with the carousel handling its own complexity while this component manages layout.

__tests__/hooks/useWaveDropsLeaderboard.extra.test.ts (1)

48-77: LGTM! Tests correctly updated to match new hook signature.

The tests properly reflect the removal of connectedProfileHandle from the hook API and follow testing best practices including clear test names, proper mocking, and the Arrange-Act-Assert pattern.

components/waves/leaderboard/drops/WaveLeaderboardDrops.tsx (2)

28-33: LGTM! Clean removal of authentication context dependency.

The hook invocation correctly reflects the simplified API without connectedProfileHandle, aligning with the broader refactoring to remove AuthContext dependencies from the leaderboard data fetching flow.


35-39: LGTM! Proper async handling in intersection observer.

The intersection observer callback correctly uses async/await for the fetchNextPage call, which is appropriate since it returns a Promise. The guard conditions ensure pagination only triggers when appropriate.

__tests__/hooks/useWaveDropsLeaderboard.test.ts (1)

38-86: LGTM! Comprehensive test coverage with correct signature updates.

The tests properly validate the hook's core functionality including pagination (manualFetch), lifecycle management (query cleanup on unmount), and edge case handling (no pagination when no more pages). All invocations correctly use the simplified API without connectedProfileHandle.

hooks/useWaveDropsLeaderboard.ts (2)

180-180: LGTM! Query now runs independently of authentication state.

Removing the connectedProfileHandle check from the enabled condition simplifies the hook and aligns with the PR's objective to remove authentication context dependencies from wave leaderboard components.


288-288: LGTM! Dependency array correctly includes refetch.

Adding refetch to the dependency array ensures the effect properly responds to changes. While refetch from react-query is typically stable and shouldn't cause unnecessary re-renders, including it is the correct approach for completeness.

app/page.tsx (2)

6-12: LGTM! Simplified page component delegates to client component.

The refactoring correctly moves data fetching responsibilities to the HomePageContent client component, which aligns with the PR's architecture changes. The page component now serves as a minimal wrapper.


14-19: LGTM! Metadata generation correctly uses the getAppMetadata helper.

The synchronous generateMetadata function properly uses the getAppMetadata helper as per coding guidelines.

Based on coding guidelines.

components/waves/leaderboard/gallery/WaveLeaderboardGallery.tsx (2)

22-25: LGTM! Hook usage simplified by removing authentication dependency.

The removal of connectedProfileHandle correctly aligns with the updated hook signature and the PR's objective to remove authentication context dependencies.


42-43: Verify consistency of media detection logic across similar gallery components.

The filter checking only drop.parts[0]?.media.length differs from the approach in WaveSmallLeaderboardItemContent (line 29), which checks all parts: drop.parts.filter((part) => !!part.media.length).length. While the API structure supports media in any part, and both components only display parts[0] anyway, this inconsistency could cause drops with media exclusively in parts[1] or later to be incorrectly excluded from the gallery while being included elsewhere.

components/home/carousel/SubmissionCarousel.tsx (3)

30-32: Media detection only checks the first part.

Consistent with changes in WaveLeaderboardGallery.tsx, this filter only examines drop.parts[0]?.media.length. If drops can have media in subsequent parts (e.g., parts[1], parts[2]), those drops will be excluded from the carousel.

See verification script in the review comment for WaveLeaderboardGallery.tsx line 42-43 to check if multi-part drops exist in the codebase.


17-21: LGTM! Proper use of the leaderboard hook with polling control.

The hook correctly pauses polling when waveId is unavailable, and uses the RATING_PREDICTION sort to show top-rated submissions. This aligns with the updated hook signature that no longer requires connectedProfileHandle.


183-183: No action required — the current implementation is correct.

The SubmissionArtworkCard component accepts an optional onClick prop (marked with ?), so omitting it is valid. The button wrapper properly handles click events via its own onClick={scrollToIndex(index)} handler. Placing onClick on both the button and the internal card div would create duplicate handlers, so the current pattern—where the button manages the click interaction—is the intended design. The card's tw-cursor-pointer and hover styling (hover:tw-scale-[1.02]) provide visual feedback without requiring an explicit onClick prop.

Likely an incorrect or invalid review comment.

Comment thread components/home/carousel/CarouselActiveItemDetails.tsx Outdated
Comment thread components/home/carousel/CarouselArrow.tsx Outdated
Comment thread components/waves/small-leaderboard/WaveSmallLeaderboard.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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

🤖 Fix all issues with AI agents
In @components/home/now-minting/NowMintingCountdownError.tsx:
- Around line 10-12: NowMintingCountdownError renders a Retry button with no
click handler; add an onRetry callback prop to the component (e.g., prop name
onRetry: () => void), update the component signature to accept onRetry, wire the
Retry button's onClick to call onRetry, and update the prop types/TS interface
and any callers to pass the handler (or default to a no-op to avoid undefined
calls) so clicking Retry actually triggers a retry action.

In @components/home/now-minting/NowMintingCountdownLoading.tsx:
- Around line 1-12: The JSX contains inline explanatory comments inside
NowMintingCountdownLoading (three comment nodes describing "Label skeleton",
"Time skeleton", "Button skeleton"); remove those JSX comments so the component
only returns the three divs with their className attributes, leaving structure
and styling intact (do not change component name NowMintingCountdownLoading or
the div className values).

In @components/home/now-minting/NowMintingDetails.tsx:
- Around line 35-41: The component passes nft.metadata (which may be undefined)
into getFileTypeFromMetadata and getDimensionsFromMetadata causing potential
crashes; add null-safety by checking nft.metadata before calling them (e.g.,
compute fileType and dimensions only if nft.metadata is truthy, otherwise pass a
safe default like undefined) or modify the helper functions
getFileTypeFromMetadata and getDimensionsFromMetadata to defensively handle
undefined metadata (use optional chaining and fallbacks when accessing
metadata.image_details.format and similar fields) so NowMintingDetailsAccordion
always receives safe values.

In @components/home/now-minting/NowMintingStatsGrid.tsx:
- Around line 17-18: The code defaults status to "active" when manifoldClaim is
null, causing a misleading UI; change the assignment in NowMintingStatsGrid so
status does not default (e.g., const status = manifoldClaim?.status ??
undefined) and update the component's render logic that uses status (or the
useMemesManifoldClaim hook consumer) to show a loading/skeleton state while
manifoldClaim is null/undefined instead of displaying "Active"; ensure
references to manifoldClaim, useMemesManifoldClaim, and status are updated
accordingly.

In @components/ipfs/IPFSContext.tsx:
- Around line 96-98: resolveIpfsUrl now returns synchronously via
resolveIpfsUrlSync; update call sites: in
__tests__/components/ipfs/IPFSContext.test.tsx remove await from
resolveIpfsUrl(...) calls and assert the immediate string/null return instead of
awaiting a Promise, and in hooks/useResolvedIpfsUrl.ts change the react-query
queryFn to wrap the sync call (e.g. return Promise.resolve(resolveIpfsUrl(src)))
when src is truthy (and return Promise.resolve(null) when falsy) so the queryFn
still returns a Promise while using the synchronous resolver.

In @docs/home-page/carousel.md:
- Line 9: The markdown fenced code blocks containing ASCII art in
docs/home-page/carousel.md (the blocks at lines referenced: 9, 20, 31, 43) are
missing language identifiers; update each opening fence to include a language
token such as "text" (e.g., change ``` to ```text) so the four ASCII art blocks
are explicitly marked and the markdown linter warnings are resolved.

In @hooks/useCountdown.ts:
- Around line 82-89: The interval is cleared when getInterval() changes
(crossing the 24-hour threshold) but no new interval is created, so the
countdown stops; modify the block that creates the interval so that when
newInterval !== intervalMs you clear the old interval and immediately create a
new setInterval using newInterval, update whatever holder for intervalMs
(state/ref) to newInterval, and ensure you still call forceUpdate() on each tick
and clear the interval during cleanup to avoid duplicate timers; reference the
existing symbols getInterval, intervalMs, interval, and forceUpdate (and
targetTimestampSeconds if used for dependency) when making this change.
🧹 Nitpick comments (13)
components/home/now-minting/NowMintingSection.tsx (1)

8-8: Consider handling the error state from useNowMinting.

The hook returns an error property (visible in the relevant snippet from hooks/useNowMinting.ts), but it's not currently destructured or handled. If the fetch fails, users won't see any feedback. Consider adding error handling for better UX.

♻️ Proposed enhancement
-  const { nft, isFetching } = useNowMinting();
+  const { nft, isFetching, error } = useNowMinting();

  if (isFetching && !nft) {
    return (
      <section className="tw-py-8">
        <h2 className="tw-mb-4 tw-text-lg tw-font-medium tw-text-iron-50">
          Now minting
        </h2>
        <div className="tw-text-iron-400">Loading...</div>
      </section>
    );
  }

+  if (error) {
+    return (
+      <section className="tw-py-8">
+        <h2 className="tw-mb-4 tw-text-lg tw-font-medium tw-text-iron-50">
+          Now minting
+        </h2>
+        <div className="tw-text-iron-400">Failed to load minting data</div>
+      </section>
+    );
+  }
+
  if (!nft) {
    return null;
  }
utils/timeFormatters.ts (1)

1-5: Consider removing JSDoc comments per coding guidelines.

The coding guidelines specify: "Do not include any comments in the code; it should be self-explanatory" for TypeScript files. While these JSDoc comments provide useful API documentation, consider removing them or using self-documenting function names and types instead.

As per coding guidelines, TSDoc comments should be avoided in favor of clear, self-explanatory code.

Also applies to: 43-49

components/home/now-minting/NowMintingArtwork.tsx (1)

20-28: Consider adding error handling to the video element.

While the video implementation is functional with good defaults (autoPlay, muted, playsInline, poster), adding an onError handler would improve robustness if the video URL fails to load.

♻️ Add error handling
         {hasVideo ? (
           <video
             src={animationUrl}
             poster={imageUrl}
             autoPlay
             loop
             muted
             playsInline
             className="tw-size-full tw-object-cover"
+            onError={(e) => {
+              e.currentTarget.style.display = 'none';
+            }}
           />
hooks/useWaveDropsLeaderboard.ts (1)

282-289: Adding refetch to dependency array may cause unnecessary effect re-runs.

While refetch is used inside the effect, react-query's refetch function identity can change on re-renders. Consider using useEffectEvent to wrap the refetch logic, or verify that react-query guarantees stable identity for refetch.

Based on learnings, useEffectEvent is recommended for non-reactive logic inside Effects to read the latest props/state without causing unnecessary re-runs.

hooks/useMintCountdownState.ts (1)

47-49: Error derivation logic could be simplified.

The condition errorFromCallback && (!manifoldClaim || manifoldClaim.isError) means an error is shown only if the callback fired AND (no data OR data has error). However, if manifoldClaim.isError is true, wouldn't that alone indicate an error regardless of the callback?

Consider clarifying the intent or simplifying:

💡 Potential simplification
-  // Derive error state: callback fired AND (no data OR data has error)
-  const isError =
-    errorFromCallback && (!manifoldClaim || manifoldClaim.isError);
+  // Show error if callback fired or if manifoldClaim indicates error
+  const isError = errorFromCallback || manifoldClaim?.isError;

If the current logic is intentional (requiring both conditions), consider adding a more detailed comment explaining why both are needed.

components/home/now-minting/NowMintingDetails.tsx (1)

16-19: Consider extracting formatEth outside the component.

The formatEth function is recreated on every render. Since it has no dependencies on component state or props, it can be moved outside the component for better performance.

♻️ Proposed refactor
+const formatEth = (value: number) => {
+  if (value === 0) return "0 ETH";
+  return `${value.toFixed(5)} ETH`;
+};
+
 export default function NowMintingDetails({ nft }: NowMintingDetailsProps) {
-  const formatEth = (value: number) => {
-    if (value === 0) return "0 ETH";
-    return `${value.toFixed(5)} ETH`;
-  };
-
   return (
components/home/now-minting/NowMintingCountdownActive.tsx (1)

22-27: Consider using Link styling directly instead of nesting a button inside Link.

Wrapping a <button> inside <Link> creates nested interactive elements which can cause accessibility issues (screen readers may announce both). Next.js Link renders an <a> tag, so the button is semantically redundant.

♻️ Suggested refactor
       {countdown.showMintBtn ? (
-        <Link href="/the-memes/mint">
-          <button className="tw-h-12 tw-w-full tw-rounded-lg tw-bg-primary-500 tw-font-semibold tw-text-white tw-transition-opacity hover:tw-opacity-90">
-            Mint
-          </button>
-        </Link>
+        <Link
+          href="/the-memes/mint"
+          className="tw-flex tw-h-12 tw-w-full tw-items-center tw-justify-center tw-rounded-lg tw-bg-primary-500 tw-font-semibold tw-text-white tw-transition-opacity hover:tw-opacity-90"
+        >
+          Mint
+        </Link>
       ) : (
components/home/now-minting/NowMintingHeader.tsx (1)

18-21: Consider handling the loading state for better UX.

The useIdentity hook returns isLoading which is currently unused. While the placeholder div provides a fallback when profile?.pfp is falsy, users see the same placeholder during loading and when there's genuinely no profile picture. Consider adding a subtle loading indicator or skeleton for the avatar.

docs/home-page/now-minting.md (4)

23-51: Add language specifier to fenced code block.

The component hierarchy diagram code block is missing a language specifier. For ASCII-art diagrams, use text or plaintext to satisfy markdown linting.

📝 Suggested fix
-```
+```text
 HomePageContent.tsx
 └── NowMintingSection/

57-68: Add language specifier to fenced code block.

📝 Suggested fix
-```
+```text
 components/home/now-minting/

136-140: Add language specifier to fenced code block.

📝 Suggested fix
-```
+```text
 [CARD #667]                    ← Small badge, iron-400 text

236-240: Add language specifier to fenced code block.

📝 Suggested fix
-```
+```text
 PUBLIC PHASE ENDS IN          ← Label, small caps
components/home/now-minting/NowMintingCountdown.tsx (1)

31-39: Remove commented-out debug code.

Per coding guidelines, code should be self-explanatory without comments. This debug/test code should be removed before merging.

🧹 Remove debug code
 function NowMintingCountdownContent({
   state,
 }: {
   readonly state: MintCountdownState;
 }) {
-  // const tempState: MintCountdownState = {
-  //   type: "countdown",
-  //   countdown: {
-  //     title: "something",
-  //     targetDate: 123,
-  //     showAllowlistInfo: true,
-  //     showMintBtn: true,
-  //   },
-  // };
   switch (state.type) {
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 027fffe and 72197e1.

📒 Files selected for processing (26)
  • components/home/HomePageContent.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/home/now-minting/NowMintingCountdownError.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/index.ts
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • docs/helpers/you-might-not-need-an-effect.md
  • docs/home-page/carousel.md
  • docs/home-page/now-minting.md
  • hooks/useCountdown.ts
  • hooks/useMintCountdownState.ts
  • hooks/useNowMinting.ts
  • hooks/useWaveDropsLeaderboard.ts
  • utils/timeFormatters.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/HomePageContent.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • hooks/useMintCountdownState.ts
  • components/home/now-minting/NowMintingCountdownError.tsx
  • hooks/useNowMinting.ts
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • hooks/useCountdown.ts
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • hooks/useWaveDropsLeaderboard.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingCountdownError.tsx
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • hooks/useMintCountdownState.ts
  • components/home/now-minting/NowMintingCountdownError.tsx
  • hooks/useNowMinting.ts
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • hooks/useCountdown.ts
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • hooks/useWaveDropsLeaderboard.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingCountdownError.tsx
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • hooks/useMintCountdownState.ts
  • components/home/now-minting/NowMintingCountdownError.tsx
  • hooks/useNowMinting.ts
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • hooks/useCountdown.ts
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • hooks/useWaveDropsLeaderboard.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • hooks/useMintCountdownState.ts
  • components/home/now-minting/NowMintingCountdownError.tsx
  • hooks/useNowMinting.ts
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • hooks/useCountdown.ts
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • hooks/useWaveDropsLeaderboard.ts
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingCountdownFinalized.tsx
  • components/home/now-minting/NowMintingCountdownSoldOut.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • hooks/useMintCountdownState.ts
  • components/home/now-minting/NowMintingCountdownError.tsx
  • hooks/useNowMinting.ts
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • hooks/useCountdown.ts
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/ipfs/IPFSContext.tsx
  • components/react-query-wrapper/ReactQueryWrapper.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • hooks/useWaveDropsLeaderboard.ts
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • utils/timeFormatters.ts
  • components/home/now-minting/index.ts
  • hooks/useMintCountdownState.ts
  • hooks/useNowMinting.ts
  • hooks/useCountdown.ts
  • hooks/useWaveDropsLeaderboard.ts
🧠 Learnings (11)
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useNowMinting.ts
  • docs/helpers/you-might-not-need-an-effect.md
  • hooks/useWaveDropsLeaderboard.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use `useMemo` instead.

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects; if the Effect only derives state, compute during render instead

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
  • hooks/useCountdown.ts
  • hooks/useWaveDropsLeaderboard.ts
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` when listening to external events but needing the latest props/state without re-running the Effect

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Move data fetching from client Effects to Server Components; mutations go through Server Actions (`'use server'`)

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Prefer Server Components over Client Components where possible. Use Server Components with inline fetches for data reads. Use Server Functions / Server Actions (`'use server'`) for mutations. Avoid client Effects for data fetching unless truly necessary.

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to app/**/*.{ts,tsx} : Prefer Server Components with inline fetches for data reads; use Server Functions/Server Actions (`'use server'`) for mutations

Applied to files:

  • docs/helpers/you-might-not-need-an-effect.md
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,jsx} : Replace `<img>` elements with `<Image />` from `next/image`

Applied to files:

  • components/home/now-minting/NowMintingArtwork.tsx
🧬 Code graph analysis (11)
components/home/now-minting/NowMintingSection.tsx (3)
hooks/useNowMinting.ts (1)
  • useNowMinting (11-22)
components/home/now-minting/NowMintingArtwork.tsx (1)
  • NowMintingArtwork (9-35)
components/home/now-minting/NowMintingDetails.tsx (1)
  • NowMintingDetails (15-46)
components/home/now-minting/NowMintingDetails.tsx (6)
entities/INFT.ts (1)
  • NFTWithMemesExtendedData (84-84)
components/home/now-minting/NowMintingHeader.tsx (1)
  • NowMintingHeader (13-45)
components/home/now-minting/NowMintingStatsGrid.tsx (1)
  • NowMintingStatsGrid (11-30)
components/home/now-minting/NowMintingDetailsAccordion.tsx (1)
  • NowMintingDetailsAccordion (11-56)
helpers/nft.helpers.ts (2)
  • getFileTypeFromMetadata (9-11)
  • getDimensionsFromMetadata (13-19)
components/home/now-minting/NowMintingCountdown.tsx (1)
  • NowMintingCountdown (15-24)
utils/timeFormatters.ts (1)
helpers/time.ts (6)
  • now (7-9)
  • hours (42-44)
  • minutes (38-40)
  • days (46-48)
  • diff (158-160)
  • seconds (34-36)
components/home/now-minting/NowMintingDetailsAccordion.tsx (1)
helpers/Helpers.ts (1)
  • printMintDate (348-361)
hooks/useMintCountdownState.ts (2)
hooks/useManifoldClaim.ts (1)
  • useMemesManifoldClaim (237-245)
components/cookies/CookieConsentContext.tsx (1)
  • useCookieConsent (45-52)
hooks/useNowMinting.ts (1)
entities/INFT.ts (1)
  • NFTWithMemesExtendedData (84-84)
components/home/now-minting/NowMintingCountdown.tsx (6)
hooks/useMintCountdownState.ts (2)
  • useMintCountdownState (30-92)
  • MintCountdownState (19-24)
components/home/now-minting/NowMintingCountdownLoading.tsx (1)
  • NowMintingCountdownLoading (1-12)
components/home/now-minting/NowMintingCountdownError.tsx (1)
  • NowMintingCountdownError (1-15)
components/home/now-minting/NowMintingCountdownSoldOut.tsx (1)
  • NowMintingCountdownSoldOut (1-18)
components/home/now-minting/NowMintingCountdownFinalized.tsx (1)
  • NowMintingCountdownFinalized (1-13)
components/home/now-minting/NowMintingCountdownActive.tsx (1)
  • NowMintingCountdownActive (9-33)
components/home/now-minting/NowMintingStatsGrid.tsx (2)
hooks/useManifoldClaim.ts (1)
  • useMemesManifoldClaim (237-245)
components/home/now-minting/NowMintingStatsItem.tsx (1)
  • NowMintingStatsItem (7-23)
components/home/now-minting/NowMintingHeader.tsx (2)
hooks/useIdentity.ts (1)
  • useIdentity (18-34)
components/ipfs/IPFSContext.tsx (1)
  • resolveIpfsUrl (96-98)
hooks/useCountdown.ts (1)
utils/timeFormatters.ts (2)
  • formatCountdown (6-41)
  • formatCountdownAdaptive (50-71)
components/home/now-minting/NowMintingCountdownActive.tsx (2)
hooks/useMintCountdownState.ts (1)
  • CountdownData (12-17)
hooks/useCountdown.ts (1)
  • useCountdownAdaptive (64-96)
🪛 LanguageTool
docs/helpers/you-might-not-need-an-effect.md

[grammar] ~16-~16: Use a hyphen to join words.
Context: ...rks provide more efficient built-in data fetching mechanisms than writing Effects...

(QB_NEW_EN_HYPHEN)


[style] ~43-~43: Consider using a different verb to strengthen your wording.
Context: ...ad, calculate it during rendering. This makes your code faster (you avoid the extra “cascading” update...

(MAKE_XXX_FASTER)


[style] ~72-~72: The phrase ‘in many cases’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others.
Context: ...eliminating the need for manual useMemo in many cases. import { useMemo, useState } from 're...

(IN_MANY_STYLE_CASES)


[style] ~103-~103: Consider using a different verb for a more formal wording.
Context: ...a comment on a wrong user’s profile. To fix the issue, you want to clear out the co...

(FIX_RESOLVE)


[style] ~167-~167: To elevate your writing, try using a synonym here.
Context: ... from previous renders like this can be hard to understand, but it’s better than upd...

(HARD_TO)


[style] ~256-~256: This phrase is redundant. Consider writing “moment” or “time”.
Context: ...ant to send the request at one specific moment in time: when the user presses the button. It s...

(MOMENT_IN_TIME)


[style] ~512-~512: This phrase is redundant. Consider using “outside”.
Context: ...ents may need to subscribe to some data outside of the React state. This data could be fro...

(OUTSIDE_OF)


[grammar] ~567-~567: Use a hyphen to join words.
Context: ...hing. It is quite common to write a data fetching Effect like this: function Sea...

(QB_NEW_EN_HYPHEN)


[grammar] ~619-~619: Use a hyphen to join words.
Context: ...rks provide more efficient built-in data fetching mechanisms than fetching data i...

(QB_NEW_EN_HYPHEN)


[style] ~658-~658: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...onent tree, pass a different key to it. To reset a particular bit of state in resp...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🪛 markdownlint-cli2 (0.18.1)
docs/home-page/now-minting.md

23-23: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


57-57: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


136-136: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


168-168: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


236-236: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/home-page/carousel.md

9-9: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


20-20: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


31-31: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


43-43: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (20)
docs/home-page/carousel.md (1)

1-76: Documentation structure and content look solid.

The carousel specification is well-organized with clear layout diagrams, responsive behavior documentation, and component hierarchy. The mappings to reusable components (e.g., DropListItemContentMedia for ArtworkCard) and animation/interaction details provide implementers with sufficient context.

components/home/now-minting/NowMintingCountdownFinalized.tsx (1)

1-13: LGTM!

Clean, simple presentational component with proper TailwindCSS styling.

components/home/now-minting/index.ts (1)

1-1: LGTM!

Standard re-export pattern, no issues.

components/react-query-wrapper/ReactQueryWrapper.tsx (1)

67-67: LGTM!

Clean enum addition following the existing pattern, properly integrated with the new useNowMinting hook.

utils/timeFormatters.ts (2)

7-8: LGTM! Improved null check.

The change from a falsy check to strict null comparison (timestamp === null) is more explicit and correct. Edge case timestamp === 0 would still be handled properly by the subsequent "Already passed" check at Line 13.


50-71: LGTM! Solid adaptive countdown logic.

The function correctly handles the two display modes (approximate "Xd Yh" vs. precise "HH:MM:SS") based on time remaining. Calculations and edge cases (past timestamps, padding) are handled appropriately.

components/home/now-minting/NowMintingDetailsAccordion.tsx (1)

1-56: LGTM! Clean accordion implementation.

The component follows all coding guidelines with readonly props, TailwindCSS styling, and proper TypeScript usage. The details/summary pattern provides native accessibility, and the chevron animation is a nice touch.

hooks/useNowMinting.ts (1)

1-22: LGTM! Proper react-query implementation.

The hook correctly uses react-query for data fetching as required by coding guidelines and learnings. The structure is clean with proper TypeScript typing and follows established patterns in the codebase.

Based on learnings, react-query should be used for data fetching.

components/home/now-minting/NowMintingArtwork.tsx (1)

1-35: LGTM! Proper Next.js Image usage.

The component correctly uses next/image instead of <img> as required by coding guidelines and learnings. Props are properly readonly, and the conditional video/image rendering is well-structured with appropriate fallbacks.

Based on learnings, <img> elements should be replaced with <Image /> from next/image.

components/home/now-minting/NowMintingStatsItem.tsx (1)

1-23: LGTM! Clean stats item component.

The component is well-structured with proper readonly props, TypeScript typing, and TailwindCSS styling. The conditional rendering for the active status indicator is straightforward and effective.

hooks/useWaveDropsLeaderboard.ts (2)

181-184: LGTM - Enable condition correctly updated.

The query is now correctly enabled based on waveId presence rather than connectedProfileHandle, which aligns with the PR objective of removing authentication dependencies from wave leaderboard components.


118-147: Dependencies are implicit but safe; no practical stale closure risk here.

The effect captures sort and waveId explicitly and derives sortDirection from sort, so queryFn always has current values when the effect re-runs. Since queryKey is recreated every render anyway (not memoized), it's used fresh each time. React's exhaustive-deps is disabled in your ESLint config, so this isn't a linting issue, and the code functions correctly.

components/home/now-minting/NowMintingStatsGrid.tsx (1)

22-29: LGTM - Clean render-time computation.

The component correctly derives statusLabel during render instead of using an Effect, following best practices from the coding guidelines.

docs/helpers/you-might-not-need-an-effect.md (1)

1-663: LGTM - Valuable documentation addition.

This documentation aligns well with the project's coding guidelines regarding Effect usage. It provides clear guidance on when to use render-time calculations, useMemo, and event handlers instead of Effects.

Minor style suggestions from static analysis (hyphenation of "data-fetching", "hard to" → "difficult to") are optional improvements that don't affect the document's utility.

hooks/useMintCountdownState.ts (2)

36-41: Render-time state reset pattern is appropriate here.

This follows the "adjusting state during render" pattern documented in the new you-might-not-need-an-effect.md file. It correctly resets errorFromCallback when nftId changes without using an Effect, avoiding extra render cycles.


56-91: LGTM - Well-structured discriminated union state.

The useMemo correctly derives the state with appropriate dependencies. The discriminated union pattern (MintCountdownState) makes it easy for consumers to handle all cases exhaustively.

components/home/now-minting/NowMintingCountdownSoldOut.tsx (1)

1-18: LGTM - Clean presentational component.

The sold-out state component is correctly implemented with a disabled button and appropriate styling. No interactivity needed since the item is sold out.

components/home/now-minting/NowMintingDetails.tsx (1)

21-44: LGTM - Clean component composition.

The component properly composes the Now Minting sub-components with appropriate prop drilling. The structure is clear and follows a logical layout order (header → stats → accordion → countdown).

hooks/useCountdown.ts (1)

14-55: LGTM - Clean render-time calculation pattern.

The refactor to use useReducer for triggering re-renders while calculating the display value during render aligns well with React best practices and the coding guidelines to avoid unnecessary Effects for state derivation.

components/home/now-minting/NowMintingCountdown.tsx (1)

40-51: LGTM - Clean state machine pattern.

The switch statement provides exhaustive handling of all MintCountdownState variants, and TypeScript will catch any missing cases. The delegation to specific subcomponents keeps this component focused on orchestration.

Comment thread components/home/now-minting/NowMintingCountdownError.tsx Outdated
Comment thread components/home/now-minting/NowMintingCountdownLoading.tsx
Comment thread components/home/now-minting/NowMintingDetails.tsx
Comment thread components/home/now-minting/NowMintingStatsGrid.tsx Outdated
Comment thread components/ipfs/IPFSContext.tsx
Comment thread docs/home-page/carousel.md
Comment thread hooks/useCountdown.ts Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In @hooks/useCountdown.ts:
- Around line 81-97: The createInterval function uses recursion (createInterval
-> createInterval) which can spawn overlapping intervals; instead, stop creating
new intervals from inside the interval callback and restart the timer from
outside: when the callback detects a needed interval change (use getInterval,
intervalRef, intervalMsRef, forceUpdate), clear intervalRef.current and set a
flag or update a local ref/state indicating the desired newInterval, then let
the surrounding effect or a separate non-recursive routine observe that flag/ref
and call createInterval(newInterval) once; remove the recursive call at the end
of the callback so only one interval exists at a time and restarting is
performed deterministically by the effect or a scheduled task.
🧹 Nitpick comments (4)
components/home/now-minting/NowMintingCountdown.tsx (1)

26-43: Consider adding an exhaustiveness check for future-proofing.

The switch statement handles all current MintCountdownState variants correctly. Adding a default case with a never assertion would provide a runtime safeguard if the union type is extended in the future.

♻️ Optional: Add exhaustiveness check
 function NowMintingCountdownContent({
   state,
 }: {
   readonly state: MintCountdownState;
 }) {
   switch (state.type) {
     case "loading":
       return <NowMintingCountdownLoading />;
     case "error":
       return <NowMintingCountdownError />;
     case "sold_out":
       return <NowMintingCountdownSoldOut />;
     case "finalized":
       return <NowMintingCountdownFinalized />;
     case "countdown":
       return <NowMintingCountdownActive countdown={state.countdown} />;
+    default: {
+      const _exhaustive: never = state;
+      return _exhaustive;
+    }
   }
 }
components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (2)

3-3: Consider importing FC directly instead of using React.FC.

The import statement already uses direct imports for useMemo, but the component declaration still uses React.FC. For consistency with the coding guidelines, consider importing FC directly.

♻️ Proposed refactor
-import React, { useMemo } from "react";
+import { type FC, useMemo } from "react";
-export const WaveSmallLeaderboard: React.FC<WaveSmallLeaderboardProps> = ({
+export const WaveSmallLeaderboard: FC<WaveSmallLeaderboardProps> = ({

Based on learnings, prefer direct named imports from React over namespace usage.

Also applies to: 15-15


26-30: Consider explicit promise handling for fetchNextPage.

The current pattern fetchNextPage().then() with no arguments doesn't handle potential errors during pagination. Consider either explicitly voiding the promise or adding error handling.

♻️ Proposed refactor options

Option 1: Explicit void (if errors are handled elsewhere):

-      fetchNextPage().then();
+      void fetchNextPage();

Option 2: Add error handling (if errors should be caught):

-      fetchNextPage().then();
+      fetchNextPage().catch((error) => {
+        console.error("Failed to fetch next page:", error);
+      });
hooks/useCountdown.ts (1)

25-37: Remove redundant null check.

Inside getUpdateInterval(), the check if (targetTime === null) return 0; at line 26 is redundant. This function is only invoked after confirming targetTime !== null at line 20, so targetTime is guaranteed to be a number here.

♻️ Proposed cleanup
 function getUpdateInterval(): number {
-  if (targetTime === null) return 0;
   const timeRemaining = targetTime - Date.now();

   if (timeRemaining < 60 * 60 * 1000) {
     return 60 * 1000; // 1 minute updates when < 1 hour away
   }

   if (timeRemaining < 24 * 60 * 60 * 1000) {
     return 5 * 60 * 1000; // 5 minute updates when < 1 day away
   }
   return 60 * 60 * 1000; // 1 hour updates otherwise
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72197e1 and f227c4f.

📒 Files selected for processing (6)
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/now-minting/NowMintingCountdown.tsx
  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • hooks/useCountdown.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/home/now-minting/NowMintingCountdownLoading.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/CarouselArrow.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/now-minting/NowMintingCountdown.tsx
  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • hooks/useCountdown.ts
🧠 Learnings (8)
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use `useMemo` instead.

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • hooks/useCountdown.ts
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Fix issues with modernization aligned to React 19.2, React Compiler, and Next.js 16 conventions. Do not add `// eslint-disable` comments unless explicitly instructed.

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Move data fetching from client Effects to Server Components; mutations go through Server Actions (`'use server'`)

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` when listening to external events but needing the latest props/state without re-running the Effect

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Prefer direct named imports from React (`useMemo`, `useRef`, `FC`) over `React.` namespace usage

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
🧬 Code graph analysis (2)
components/home/now-minting/NowMintingCountdown.tsx (6)
hooks/useMintCountdownState.ts (2)
  • useMintCountdownState (30-92)
  • MintCountdownState (19-24)
components/home/now-minting/NowMintingCountdownLoading.tsx (1)
  • NowMintingCountdownLoading (1-9)
components/home/now-minting/NowMintingCountdownError.tsx (1)
  • NowMintingCountdownError (1-15)
components/home/now-minting/NowMintingCountdownSoldOut.tsx (1)
  • NowMintingCountdownSoldOut (1-18)
components/home/now-minting/NowMintingCountdownFinalized.tsx (1)
  • NowMintingCountdownFinalized (1-13)
components/home/now-minting/NowMintingCountdownActive.tsx (1)
  • NowMintingCountdownActive (9-33)
hooks/useCountdown.ts (1)
utils/timeFormatters.ts (2)
  • formatCountdown (6-41)
  • formatCountdownAdaptive (50-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/home/now-minting/NowMintingCountdown.tsx (3)

1-9: LGTM!

Imports are well-organized with the type import properly separated and all required sub-components imported.


11-13: LGTM!

Interface correctly uses readonly modifier as per coding guidelines.


15-24: LGTM!

Clean component implementation with proper hook usage and TailwindCSS styling.

components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (1)

36-38: LGTM! Styling updates align with design conventions.

The TailwindCSS class updates for both the empty state message and loading indicator are appropriate and consistent with the broader design system changes in this PR.

Also applies to: 52-54

Comment thread hooks/useCountdown.ts
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 0

🧹 Nitpick comments (5)
hooks/useCountdown.ts (3)

9-55: Remove inline comments per coding guidelines.

The hook has multiple inline comments (lines 15, 19, 24, 42, 49, 53) that should be removed. JSDoc at lines 9-13 can be retained for API documentation, but inline implementation comments violate the guideline that code should be self-explanatory.

Suggested cleanup
 export function useCountdown(targetTime: number | null): string {
-  // Use reducer to trigger re-renders; display value is calculated during render
   const [, forceUpdate] = useReducer((x) => x + 1, 0);

   useEffect(() => {
-    // Skip if no target time or already passed
     if (targetTime === null || Date.now() >= targetTime) {
       return;
     }

-    // Determine update frequency based on time remaining
     function getUpdateInterval(): number {
       if (targetTime === null) return 0;
       const timeRemaining = targetTime - Date.now();

       if (timeRemaining < 60 * 60 * 1000) {
         return 60 * 1000;
       }

       if (timeRemaining < 24 * 60 * 60 * 1000) {
         return 5 * 60 * 1000;
       }
       return 60 * 60 * 1000;
     }

-    // Set interval for updates
     const intervalTime = getUpdateInterval();
     const interval = setInterval(() => {
-      // Stop updating if target reached
       if (Date.now() >= targetTime) {
         clearInterval(interval);
       }
       forceUpdate();
     }, intervalTime);

-    // Clean up interval on unmount or when targetTime changes
     return () => clearInterval(interval);
   }, [targetTime]);

-  // ✅ Calculate display during rendering (not in effect)
   return formatCountdown(targetTime);
 }

As per coding guidelines, code should be self-explanatory without comments.


103-119: Inefficient polling mechanism with 50ms monitoring interval.

The 50ms monitoring interval runs continuously even when no interval switch is pending, resulting in unnecessary CPU cycles (20 checks per second). This polling pattern adds complexity and is inefficient.

A cleaner approach would be to schedule the interval transition directly using setTimeout based on the time until the 24-hour threshold:

Suggested refactor using setTimeout for transition
   useEffect(() => {
     const targetMs = targetTimestampSeconds * 1000;
+    let intervalId: ReturnType<typeof setInterval> | null = null;
+    let transitionTimeoutId: ReturnType<typeof setTimeout> | null = null;

     const getInterval = () => {
       const diff = targetMs - Date.now();
       if (diff <= 0) return null;
       if (diff < 24 * 60 * 60 * 1000) return 1000;
       return 60 * 1000;
     };

-    const createInterval = (intervalMs: number) => {
-      intervalMsRef.current = intervalMs;
-      pendingIntervalRef.current = null;
-      intervalRef.current = setInterval(() => {
-        forceUpdate();
-        const newInterval = getInterval();
-        if (newInterval === null) {
-          if (intervalRef.current) clearInterval(intervalRef.current);
-          intervalRef.current = null;
-        } else if (newInterval !== intervalMsRef.current) {
-          pendingIntervalRef.current = newInterval;
-          if (intervalRef.current) clearInterval(intervalRef.current);
-          intervalRef.current = null;
-        }
-      }, intervalMs);
-    };
-
-    const checkPendingInterval = () => {
-      if (pendingIntervalRef.current !== null && intervalRef.current === null) {
-        createInterval(pendingIntervalRef.current);
-      }
-    };
+    const startUpdates = (intervalMs: number) => {
+      intervalId = setInterval(() => {
+        const newInterval = getInterval();
+        if (newInterval === null && intervalId) {
+          clearInterval(intervalId);
+          intervalId = null;
+        }
+        forceUpdate();
+      }, intervalMs);
+    };

     const intervalMs = getInterval();
     if (intervalMs === null) return;

-    createInterval(intervalMs);
+    startUpdates(intervalMs);

-    const monitorInterval = setInterval(checkPendingInterval, 50);
+    if (intervalMs === 60 * 1000) {
+      const diff = targetMs - Date.now();
+      const timeUntilSecondUpdates = diff - 24 * 60 * 60 * 1000;
+      if (timeUntilSecondUpdates > 0) {
+        transitionTimeoutId = setTimeout(() => {
+          if (intervalId) clearInterval(intervalId);
+          startUpdates(1000);
+        }, timeUntilSecondUpdates);
+      }
+    }

     return () => {
-      if (intervalRef.current) clearInterval(intervalRef.current);
-      clearInterval(monitorInterval);
-      pendingIntervalRef.current = null;
+      if (intervalId) clearInterval(intervalId);
+      if (transitionTimeoutId) clearTimeout(transitionTimeoutId);
     };
   }, [targetTimestampSeconds]);

This eliminates the need for intervalMsRef, pendingIntervalRef, and the polling monitor, reducing complexity and improving efficiency.


64-69: Remove inline comments in useCountdownAdaptive.

Similar to useCountdown, the inline comments at lines 65, 74, 87, 90, 94, 102, 114, and 124 should be removed per coding guidelines. The JSDoc at lines 57-63 can be retained for API documentation.

components/home/now-minting/NowMintingStatsGrid.tsx (1)

21-22: Consider using a ternary for clearer conditional logic.

The && operator works correctly but a ternary would make the intent more explicit for capitalizing the status string.

♻️ Clearer alternative using ternary
-  const statusLabel =
-    status && status.charAt(0).toUpperCase() + status.slice(1);
+  const statusLabel = status
+    ? status.charAt(0).toUpperCase() + status.slice(1)
+    : undefined;
components/home/now-minting/NowMintingStatsItem.tsx (1)

1-6: Optional: Simplify optional prop types.

The explicit | undefined is redundant for optional properties; ? already includes undefined in the type.

♻️ Simplified optional property types
 interface NowMintingStatsItemProps {
   readonly label: string;
-  readonly value?: string | undefined;
-  readonly status?: "active" | "upcoming" | "ended" | undefined;
+  readonly value?: string;
+  readonly status?: "active" | "upcoming" | "ended";
   readonly isLoading?: boolean;
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f227c4f and b6860f8.

📒 Files selected for processing (4)
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • hooks/useCountdown.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • hooks/useCountdown.ts
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • hooks/useCountdown.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • hooks/useCountdown.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • hooks/useCountdown.ts
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/now-minting/NowMintingStatsItem.tsx
  • hooks/useCountdown.ts
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • hooks/useCountdown.ts
🧠 Learnings (4)
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Applied to files:

  • hooks/useCountdown.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use `useMemo` instead.

Applied to files:

  • hooks/useCountdown.ts
🧬 Code graph analysis (2)
components/home/now-minting/NowMintingStatsGrid.tsx (2)
hooks/useManifoldClaim.ts (1)
  • useMemesManifoldClaim (237-245)
components/home/now-minting/NowMintingStatsItem.tsx (1)
  • NowMintingStatsItem (8-29)
hooks/useCountdown.ts (1)
utils/timeFormatters.ts (2)
  • formatCountdown (6-41)
  • formatCountdownAdaptive (50-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/home/now-minting/NowMintingStatsGrid.tsx (2)

1-9: LGTM! Clean imports and well-typed interface.

The interface follows guidelines with readonly props and appropriate typing.


24-36: LGTM! Well-structured render logic.

The grid layout correctly shows four stats, with isLoading only passed to the Status item since it's the only value derived from the hook within this component.

components/home/now-minting/NowMintingStatsItem.tsx (2)

8-16: LGTM! Clean component structure and label rendering.

The component follows React 19 functional component patterns with proper prop destructuring and TailwindCSS styling.


17-27: LGTM! Proper conditional rendering and loading states.

The loading skeleton and status indicator (green dot for "active") are well-implemented. The component correctly handles undefined values.

Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 3

🤖 Fix all issues with AI agents
In @components/home/boosted/BoostedDropCard.tsx:
- Around line 16-73: Two different components share the same name
BoostedDropCard which risks import confusion; rename this component to a
distinct name (e.g., BoostedDropCardHome) by updating the memo-wrapped component
identifier from BoostedDropCard to BoostedDropCardHome, change the exported
identifier accordingly, and run a project-wide search to update any imports that
reference this component to the new name; ensure props (drop, onClick) and
usages remain unchanged and adjust any story/tests that import the old name.

In @components/home/boosted/BoostedSection.tsx:
- Line 50: The "View all" element in BoostedSection.tsx is a non-interactive
<span> that looks actionable; replace it with a navigable element (e.g., your
router's Link component or an <a> with proper href) and attach the intended
destination or onClick handler so it actually navigates to the full list, or if
navigation isn't ready, remove it or add a clear TODO comment and visually
de-emphasize it to avoid misleading users; update the element referenced in
BoostedSection (the span with className "tw-text-sm tw-text-iron-500")
accordingly.

In @components/waves/winners/WaveWinnersSmall.tsx:
- Around line 61-65: The useEffect sets the activeDecisionPoint using
decisionPoints[0]?.id! which mixes optional chaining and a non-null assertion
unnecessarily; replace that expression with a safe, direct access (e.g.,
setActiveDecisionPoint(decisionPoints[0].id)) since you already check
decisionPoints.length > 0, or alternatively explicitly guard for a missing id
(e.g., const id = decisionPoints[0].id; if (id) setActiveDecisionPoint(id)) to
avoid masking potential null/undefined with `!`; update the useEffect that
references decisionPoints, activeDecisionPoint, and setActiveDecisionPoint
accordingly.
🧹 Nitpick comments (4)
components/home/now-minting/NowMintingStatsGrid.tsx (1)

25-37: Consider the grid item order from a UX perspective.

The current layout places items as:

Edition    | Mint price
Status     | Floor

Placing "Status" in the bottom-left position separates it from "Edition," which might feel less intuitive than grouping related metadata together (e.g., Edition + Status in the left column). Consider whether this order aligns with the intended visual hierarchy.

Alternative layout suggestion
 <div className="tw-grid tw-grid-cols-2 tw-gap-4 tw-border-y tw-border-iron-800 tw-py-4">
   <NowMintingStatsItem label="Edition" value={edition} />
-  <NowMintingStatsItem label="Mint price" value={mintPrice} />
   <NowMintingStatsItem
     label="Status"
     value={statusLabel}
     status={status}
     isLoading={isStatusLoading}
   />
+  <NowMintingStatsItem label="Mint price" value={mintPrice} />
   <NowMintingStatsItem label="Floor" value={floorPrice} />
 </div>

This would create:

Edition    | Status
Mint price | Floor
docs/home-page/next-mint-and-leading.md (1)

1-241: Comprehensive documentation with minor formatting improvements needed.

The documentation is thorough and well-structured. However, consider these optional improvements for better markdown formatting:

  1. Add language specifiers to fenced code blocks at lines 13, 42, and 145 (e.g., ```text or ```bash)
  2. Add a period after "etc" on line 241: (votes, etc.)

Based on static analysis hints.

📝 Suggested formatting fixes

For line 13 (layout diagram):

-```
+```text
 ┌─────────────────────────────────────────────────────────────────────────┐

For line 42 (directory structure):

-```
+```text
 components/home/next-mint-leading/

For line 145 (color scheme):

-```
+```text
 Background:    tw-bg-iron-900

For line 241:

-- [ ] Should we show any stats (votes, etc) on leading cards?
+- [ ] Should we show any stats (votes, etc.) on leading cards?
components/home/next-mint-leading/NextMintLeadingSection.tsx (1)

61-66: Use Next.js <Link> for internal navigation.

Per coding guidelines, internal links should use the <Link> component from Next.js instead of raw <a> tags for client-side navigation benefits.

Suggested fix
+import Link from "next/link";
 // ... at the link location:
-        <a
-          href="/waves"
+        <Link
+          href="/waves"
           className="tw-text-sm tw-text-iron-400 tw-transition-colors hover:tw-text-iron-200"
         >
           View all →
-        </a>
+        </Link>
components/home/next-mint-leading/LeadingCard.tsx (1)

14-62: Consider adding click handler for navigation.

Unlike NextMintCard and BoostedDropCard, this component has no onClick handler. If users should be able to click through to view the drop details, consider adding navigation similar to the other card components.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6860f8 and e06c61f.

📒 Files selected for processing (14)
  • components/home/HomePageContent.tsx
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/next-mint-leading/index.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • docs/home-page/next-mint-and-leading.md
  • hooks/useBoostedDrops.ts
  • hooks/waves/useWaveDecisions.ts
✅ Files skipped from review due to trivial changes (1)
  • components/home/boosted/index.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • hooks/waves/useWaveDecisions.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • hooks/waves/useWaveDecisions.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • hooks/waves/useWaveDecisions.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • hooks/waves/useWaveDecisions.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • components/home/boosted/BoostedDropCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • hooks/waves/useWaveDecisions.ts
  • components/home/now-minting/NowMintingStatsGrid.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/HomePageContent.tsx
  • components/waves/winners/WaveWinners.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • components/home/next-mint-leading/index.ts
  • hooks/useBoostedDrops.ts
  • hooks/waves/useWaveDecisions.ts
🧠 Learnings (5)
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • hooks/useBoostedDrops.ts
  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • hooks/useBoostedDrops.ts
  • hooks/waves/useWaveDecisions.ts
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use `useMemo` instead.

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Prefer direct named imports from React (`useMemo`, `useRef`, `FC`) over `React.` namespace usage

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
🧬 Code graph analysis (8)
components/home/boosted/BoostedSection.tsx (2)
hooks/useBoostedDrops.ts (1)
  • useBoostedDrops (19-43)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
hooks/useBoostedDrops.ts (2)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
types/boosted-drops.types.ts (1)
  • TIME_WINDOW_MS (7-11)
components/home/boosted/BoostedDropCard.tsx (3)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-95)
components/drops/view/BoostedDropCard.tsx (1)
  • BoostedDropCardProps (22-146)
components/home/next-mint-leading/NextMintCard.tsx (3)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
components/home/next-mint-leading/index.ts (1)
  • NextMintCard (2-2)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-95)
hooks/waves/useWaveDecisions.ts (1)
generated/models/ApiWaveDecision.ts (1)
  • ApiWaveDecision (17-45)
components/home/now-minting/NowMintingStatsGrid.tsx (2)
hooks/useManifoldClaim.ts (1)
  • useMemesManifoldClaim (237-245)
components/home/now-minting/NowMintingStatsItem.tsx (1)
  • NowMintingStatsItem (8-29)
components/home/next-mint-leading/LeadingCard.tsx (2)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-95)
components/home/HomePageContent.tsx (4)
components/home/carousel/SubmissionCarousel.tsx (1)
  • SubmissionCarousel (13-200)
components/home/now-minting/NowMintingSection.tsx (1)
  • NowMintingSection (7-40)
components/home/next-mint-leading/NextMintLeadingSection.tsx (1)
  • NextMintLeadingSection (12-81)
components/home/boosted/BoostedSection.tsx (1)
  • BoostedSection (11-65)
🪛 LanguageTool
docs/home-page/next-mint-and-leading.md

[style] ~241-~241: In American English, abbreviations like “etc.” require a period.
Context: ... - [ ] Should we show any stats (votes, etc) on leading cards? - [ ] Animation on s...

(ETC_PERIOD)

🪛 markdownlint-cli2 (0.18.1)
docs/home-page/next-mint-and-leading.md

13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


42-42: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


145-145: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (15)
components/home/now-minting/NowMintingStatsGrid.tsx (1)

17-19: This concern is invalid. The status property is required (not optional) in the ManifoldClaim interface and is always populated when the claim object is created. There is no edge case where manifoldClaim is truthy but status is undefined—when the hook returns a claim object, status is guaranteed to be one of the ManifoldClaimStatus enum values. The loading logic isStatusLoading = !manifoldClaim correctly handles all states.

components/home/HomePageContent.tsx (1)

1-17: LGTM! Clean composition pattern.

The component follows a clear composition pattern, properly uses the "use client" directive for Next.js 15, and maintains a simple, focused responsibility of assembling the home page sections.

components/waves/winners/WaveWinners.tsx (2)

28-31: Good API simplification.

The change to pass only waveId instead of the full wave object reduces coupling and aligns with the updated useWaveDecisions hook signature.


47-57: Excellent use of nullish coalescing operator.

Switching from || to ?? for array fallbacks is the correct choice. The nullish coalescing operator only triggers for null or undefined, preserving empty arrays [] as-is, whereas || would have incorrectly replaced empty arrays with the fallback value.

hooks/useBoostedDrops.ts (3)

1-22: Well-structured hook setup.

The hook follows React Query best practices with proper TypeScript types, readonly props, and clearly defined constants. The default parameter values are sensible.


23-37: Query implementation looks correct.

The query key properly includes all parameters, the time window calculation is accurate, and the API parameters are correctly formatted.


38-42: Appropriate caching strategy for real-time data.

The combination of staleTime: 60s and refetchInterval: 30s ensures boosted drops data stays fresh for real-time updates. The retry configuration with exponential backoff is well-designed.

hooks/waves/useWaveDecisions.ts (2)

6-30: Good API simplification with clearer responsibilities.

The change from accepting a full wave object to just waveId simplifies the hook's API surface. The enabled prop now has full control, which places responsibility on callers to ensure waveId is valid before enabling the query. This is a reasonable contract and aligns with React Query best practices.


32-47: Proper use of nullish coalescing in data processing.

The data processing correctly uses ?? to provide a fallback only for null or undefined, preserving empty arrays. The explicit mapping is more readable.

components/waves/winners/WaveWinnersSmall.tsx (1)

42-44: LGTM!

The hook invocation correctly updated to use waveId: wave.id matching the new useWaveDecisions signature.

components/home/next-mint-leading/index.ts (1)

1-3: LGTM!

Clean barrel export establishing the public API for the next-mint-leading module.

components/home/next-mint-leading/NextMintCard.tsx (1)

13-61: LGTM!

Well-structured component with proper fallbacks for missing media/title/author data. The title derivation chain and media handling are robust.

components/home/boosted/BoostedSection.tsx (1)

11-36: LGTM!

Clean component structure with proper loading and empty states. The useCallback for handleDropClick is appropriate since it's passed to child components.

components/home/boosted/BoostedDropCard.tsx (1)

26-29: Good accessibility pattern.

Using a <button> element with type="button" for the clickable card is the right approach for accessibility, providing proper keyboard navigation and screen reader support.

components/home/next-mint-leading/LeadingCard.tsx (1)

9-12: LGTM!

Props interface correctly uses readonly modifiers as per coding guidelines.

Comment thread components/home/boosted/BoostedDropCard.tsx Outdated
Comment thread components/home/boosted/BoostedSection.tsx Outdated
Comment thread components/waves/winners/WaveWinnersSmall.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 4

🤖 Fix all issues with AI agents
In @components/home/boosted/BoostedDropCardHome.tsx:
- Around line 34-46: Remove the JSX comments in BoostedDropCardHome.tsx that
wrap the "Boost badge" and "Content area" (and the similar comments at lines
61-62); find the JSX blocks containing the BoostIcon/boost count span
(references: BoostIcon, {drop.boosts}) and the surrounding div with className
"tw-aspect-[3/4] tw-w-full tw-overflow-hidden" and simply delete the {/* ... */}
comment nodes so the markup contains only elements and no inline JSX comments to
comply with the "no comments in code" guideline.
- Around line 16-59: BoostedDropCardHome currently renders
DropListItemContentMedia without forwarding the parent button's onClick, so
clicks on images don't trigger card navigation; update the JSX in
BoostedDropCardHome to pass onContainerClick={onClick} into
DropListItemContentMedia (ensure you reference the existing onClick prop and the
DropListItemContentMedia component) so image clicks propagate to the parent
button; note that video/audio components will need analogous prop support
separately.

In @components/home/boosted/BoostedSection.tsx:
- Around line 40-41: Remove the JSX comments in the BoostedSection component —
specifically delete the {/* Header */} comment before the div with className
"tw-mb-4 tw-flex tw-items-center tw-justify-between" and the other JSX comment
at lines 53-54; do not replace them with inline JS comments, just remove the
comment nodes so the JSX follows the repo guideline of no comments in code.
- Around line 40-51: In BoostedSection.tsx the "View all" span is
non-interactive and not keyboard-accessible; replace the span with Next.js Link
(import Link from 'next/link') pointing to the appropriate route (e.g.,
"/boosted" or the site’s boosted-drops page) so it behaves as an internal
navigation element, or alternatively replace it with a semantic <button> and add
onClick handler if it performs an action; ensure the new element preserves the
existing classes (tw-text-sm tw-text-iron-500) and includes accessible
attributes (aria-label if needed) for keyboard and screen-reader users.
🧹 Nitpick comments (3)
components/waves/winners/WaveWinnersSmall.tsx (1)

47-65: Memoize decision points transformation to prevent unnecessary effect re-runs.

The decisionPoints array is recreated on every render (lines 47-58), which causes the useEffect (lines 61-65) to run on every render even when rawDecisionPoints hasn't changed. This violates the principle of efficient dependency management.

As per coding guidelines: Remove unnecessary Effects and use useMemo for derived state.

♻️ Proposed fix using useMemo
-  // Process decision points to include UI-friendly fields
-  const decisionPoints: EnhancedDecisionPoint[] = rawDecisionPoints.map(
-    (point) => {
-      const decisionTime = point.decision_time;
-      // Create a formatted date string
-      const dateObj = new Date(decisionTime);
-      return {
-        ...point,
-        id: decisionTime.toString(), // Use decision_time as ID
-        date: dateObj.toISOString(),
-      };
-    }
-  );
+  // Process decision points to include UI-friendly fields
+  const decisionPoints: EnhancedDecisionPoint[] = useMemo(
+    () =>
+      rawDecisionPoints.map((point) => {
+        const decisionTime = point.decision_time;
+        const dateObj = new Date(decisionTime);
+        return {
+          ...point,
+          id: decisionTime.toString(),
+          date: dateObj.toISOString(),
+        };
+      }),
+    [rawDecisionPoints]
+  );

Don't forget to import useMemo:

-import { useState, memo, useEffect } from "react";
+import { useState, memo, useEffect, useMemo } from "react";
components/home/boosted/BoostedDropCardHome.tsx (1)

25-27: Null-safety hardening for display fields. drop.wave.name (and/or author.handle) may be nullable depending on the generated model; consider a fallback to avoid rendering undefined.

Also applies to: 73-75

components/home/boosted/BoostedSection.tsx (1)

17-22: Build the navigation URL with URLSearchParams (safer encoding).

Proposed refactor
   const handleDropClick = useCallback(
     (drop: ApiDrop) => {
-      router.push(`/waves?wave=${drop.wave.id}&serialNo=${drop.serial_no}`);
+      const params = new URLSearchParams({
+        wave: String(drop.wave.id),
+        serialNo: String(drop.serial_no),
+      });
+      router.push(`/waves?${params.toString()}`);
     },
     [router]
   );
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e06c61f and 09e5e49.

📒 Files selected for processing (4)
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/waves/winners/WaveWinnersSmall.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/boosted/BoostedSection.tsx
  • components/home/boosted/index.ts
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • components/home/boosted/index.ts
🧠 Learnings (8)
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{jsx,tsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of raw `<a>` tags to comply with `next/next/no-html-link-for-pages`.

Applied to files:

  • components/home/boosted/BoostedSection.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,jsx} : Use internal links via `<Link>` component from Next.js instead of `<a>` tags

Applied to files:

  • components/home/boosted/BoostedSection.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{tsx,jsx},!**/__tests__/**,!**/__mocks__/** : Use semantic HTML (`<label>`, `<output>`) over ARIA attributes when possible

Applied to files:

  • components/home/boosted/BoostedSection.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Avoid double negatives in code; prefer explicit statements and use optional chaining (`?.`)

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use `useMemo` instead.

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Prefer direct named imports from React (`useMemo`, `useRef`, `FC`) over `React.` namespace usage

Applied to files:

  • components/waves/winners/WaveWinnersSmall.tsx
🧬 Code graph analysis (2)
components/home/boosted/BoostedSection.tsx (2)
hooks/useBoostedDrops.ts (1)
  • useBoostedDrops (19-43)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
components/home/boosted/BoostedDropCardHome.tsx (2)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-237)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-95)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
components/waves/winners/WaveWinnersSmall.tsx (1)

42-42: Good alignment with updated hook signature.

The change to pass waveId: wave.id instead of the full wave object aligns well with the broader refactor toward ID-based data access patterns mentioned in the PR summary.

components/home/boosted/index.ts (1)

1-2: Clean barrel export; looks good.

components/home/boosted/BoostedSection.tsx (1)

1-65: Please ensure npm run lint is clean for these new TSX files (per guidelines).

Comment thread components/home/boosted/BoostedDropCardHome.tsx
Comment thread components/home/boosted/BoostedDropCardHome.tsx Outdated
Comment thread components/home/boosted/BoostedSection.tsx Outdated
Comment thread components/home/boosted/BoostedSection.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
components/waves/winners/DefaultWaveWinnerDropSmall.tsx (1)

141-145: Display text should fall back to primary_address when handle is undefined.

The href correctly falls back to primary_address, but the displayed text on line 143 only shows handle. If handle is undefined, the link will render with no visible text while still being clickable.

Suggested fix
                   <span className="tw-text-sm tw-font-semibold tw-text-iron-200 tw-transition-colors desktop-hover:hover:tw-text-iron-100">
-                    {drop.author.handle}
+                    {drop.author.handle ?? drop.author.primary_address}
                   </span>
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)

141-145: Display text should fall back to primary_address when handle is undefined.

Same issue as in DefaultWaveWinnerDropSmall.tsx—the link href falls back correctly but the visible text does not.

Suggested fix
                   <span className="tw-text-sm tw-font-semibold tw-text-iron-200 tw-transition-colors desktop-hover:hover:tw-text-opacity-80">
-                    {drop.author.handle}
+                    {drop.author.handle ?? drop.author.primary_address}
                   </span>
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (2)

63-65: Missing fallback for displayed invoker name.

Lines 45 and 47 use log.invoker.handle ?? log.invoker.primary_address for href and title, but Line 64 displays only log.invoker.handle. When handle is undefined, the link will navigate correctly but display nothing.

Suggested fix
              <span className="tw-text-sm tw-font-medium tw-text-iron-50 tw-transition-all tw-duration-300 desktop-hover:group-hover:tw-text-iron-300">
-               {log.invoker.handle}
+               {log.invoker.handle ?? log.invoker.primary_address}
              </span>

112-116: Bug: Fallback branch renders nothing.

This else branch executes when log.drop_author?.handle is falsy, but Line 114 tries to render log.drop_author?.handle, which will always be empty/undefined. Should display primary_address as the fallback.

Suggested fix
            ) : (
              <span className="tw-text-sm tw-font-medium tw-text-iron-50 tw-transition-all tw-duration-300 desktop-hover:group-hover:tw-text-iron-300">
-               {log.drop_author?.handle}
+               {log.drop_author?.primary_address}
              </span>
            )}
components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx (1)

38-44: Bug: Removing !! will render 0 in the DOM when media array is empty.

When drop.parts[0]?.media.length is 0, React will render the literal 0 in the DOM instead of skipping the component. JSX short-circuit evaluation with && renders numeric falsy values.

Proposed fix
-        {drop.parts[0]?.media.length && (
+        {!!drop.parts[0]?.media.length && (
           <WaveDropPartContentMedias
             activePart={drop.parts[0]}
             disableMediaInteraction={true}
             imageScale={ImageScale.AUTOx450}
           />
         )}

Alternatively, use an explicit comparison: drop.parts[0]?.media.length > 0 &&

components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx (1)

47-54: Inconsistent use of drop.rank instead of rank parameter.

The function accepts rank as a parameter but the condition checks drop.rank from the outer scope. This makes the rank parameter misleading and could cause bugs if the two values differ.

Proposed fix
  const trophyIcon = (rank: number | null, decisionTime?: number) => {
-   if (typeof drop.rank === "number") {
+   if (typeof rank === "number") {
      return (
        <WinnerDropBadge rank={rank} decisionTime={decisionTime ?? null} />
      );
    }
    return <></>;
  };
🤖 Fix all issues with AI agents
In @components/home/explore-waves/ExploreWavesSection.tsx:
- Around line 32-35: In ExploreWavesSection, before returning null when isError
is true, log the error for debugging by calling console.error with a clear
message and the error object used by the fetch hook (e.g., the variable named
error or wavesError returned alongside isError); update the conditional block
that checks isError to emit this log and then return null so the section remains
hidden but the failure is recorded.

In @components/home/hero/HeroHeader.tsx:
- Around line 9-12: The paragraph in the HeroHeader component contains Lorem
ipsum placeholder text; open the HeroHeader.tsx, find the <p> element inside the
HeroHeader component (the tw-mx-auto ... tw-text-iron-400 paragraph) and replace
the placeholder with the final marketing copy or wire it to a prop/translation
key (e.g., subtitle, heroSubtitle, or an i18n string) so real content is
rendered instead of Lorem ipsum before release.

In
@components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx:
- Line 86: The onDropClick passes log.contents["drop"]?.serial_no which can be
undefined but handleDropClick expects a number; fix by guarding the call or
making handleDropClick handle undefined: either only call onDropClick when
log.contents["drop"] is present (e.g., check log.contents["drop"] && call
handleDropClick with its serial_no) or update handleDropClick (and its use of
waveChatScroll?.requestScrollToSerialNo) to accept number | undefined and
early-return when serialNo is undefined; reference handleDropClick,
log.contents["drop"]?.serial_no and waveChatScroll?.requestScrollToSerialNo when
applying the change.
🧹 Nitpick comments (22)
components/brain/my-stream/MyStreamWave.tsx (2)

37-44: Redundant fallback in URLSearchParams construction.

useSearchParams() in Next.js App Router always returns a valid ReadonlyURLSearchParams object, and toString() always returns a string (empty if no params). The || "" fallback is unnecessary.

Suggested simplification
-      const params = new URLSearchParams(searchParams.toString() || "");
+      const params = new URLSearchParams(searchParams.toString());

74-78: Same redundant fallback pattern.

Consistent with the earlier callback, the || "" fallback is unnecessary here as well since searchParams.toString() is guaranteed to return a string.

Suggested simplification
-    const params = new URLSearchParams(searchParams.toString() || "");
+    const params = new URLSearchParams(searchParams.toString());
components/waves/winners/DefaultWaveWinnerDropSmall.tsx (1)

119-127: Replace <img> with <Image /> from next/image.

Per coding guidelines, use <Image /> from next/image instead of raw <img> elements for optimized image loading.

Suggested fix
+import Image from "next/image";

...

              {drop.author.pfp ? (
-                <img
+                <Image
                   src={getScaledImageUri(
                     drop.author.pfp,
                     ImageScale.W_AUTO_H_50
                   )}
                   alt={`${drop.author.handle ?? drop.author.primary_address}'s profile`}
                   className="tw-size-7 tw-rounded-lg tw-object-cover tw-ring-1 tw-ring-white/10"
+                  width={28}
+                  height={28}
                 />
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)

119-127: Replace <img> with <Image /> from next/image.

Same issue as in DefaultWaveWinnerDropSmall.tsx—use <Image /> from next/image per coding guidelines.

Suggested fix
+import Image from "next/image";

...

              {drop.author.pfp ? (
-                <img
+                <Image
                   src={getScaledImageUri(
                     drop.author.pfp,
                     ImageScale.W_AUTO_H_50
                   )}
                   alt={`${drop.author.handle ?? drop.author.primary_address}'s profile`}
                   className="tw-size-7 tw-rounded-lg tw-object-cover tw-ring-1 tw-ring-white/10"
+                  width={28}
+                  height={28}
                 />
docs/specs/2026-01-12-explore-waves-homepage-section.md (1)

142-151: Add language specifier to fenced code blocks.

The design specification code blocks should have a language identifier to satisfy markdown linting rules (MD040). Consider using text or plaintext for these layout descriptions.

📝 Suggested fix
-```
+```text
 Header Row:
 - Left: "Explore waves" (h2, text-xl font-semibold text-iron-50)

And similarly for the Card Layout block at line 154.

Also applies to: 154-172

components/home/explore-waves/ExploreWaveCardSkeleton.tsx (1)

3-24: Remove inline comments to comply with coding guidelines.

The component structure is self-explanatory. Per coding guidelines, comments should be removed as the code should be self-documenting.

♻️ Suggested fix
 export function ExploreWaveCardSkeleton() {
   return (
     <div className="tw-overflow-hidden tw-rounded-xl tw-bg-iron-950 tw-ring-1 tw-ring-inset tw-ring-white/10">
-      {/* Image Skeleton */}
       <div className="tw-aspect-[16/10] tw-animate-pulse tw-bg-iron-900" />
-
-      {/* Content Skeleton */}
       <div className="tw-p-4">
-        {/* Wave Name Skeleton */}
         <div className="tw-h-6 tw-w-3/4 tw-animate-pulse tw-rounded tw-bg-iron-800" />
-
-        {/* Metadata Skeleton */}
         <div className="tw-mt-2 tw-h-4 tw-w-1/2 tw-animate-pulse tw-rounded tw-bg-iron-800/60" />
-
-        {/* Message Preview Skeleton */}
         <div className="tw-mt-3 tw-flex tw-items-start tw-gap-2">
           <div className="tw-size-4 tw-flex-shrink-0 tw-animate-pulse tw-rounded tw-bg-iron-800/60" />
           <div className="tw-h-4 tw-flex-1 tw-animate-pulse tw-rounded tw-bg-iron-800/60" />
         </div>
       </div>
     </div>
   );
 }
components/home/explore-waves/ExploreWavesSection.tsx (1)

41-69: Remove inline comments to comply with coding guidelines.

The section structure is clear from the JSX hierarchy. Per coding guidelines, comments should be removed.

♻️ Suggested fix
   return (
     <section className="tw-py-8">
-      {/* Header */}
       <div className="tw-mb-6 tw-flex tw-items-start tw-justify-between tw-gap-4">
         <div>
           <h2 className="tw-m-0 tw-text-xl tw-font-semibold tw-text-iron-50">
             Explore waves
           </h2>
           <p className="tw-m-0 tw-mt-1 tw-text-sm tw-text-iron-400">
             Browse channels—jump into the conversation.
           </p>
         </div>
         <Link
           href="/discover"
           className="tw-whitespace-nowrap tw-text-sm tw-text-iron-400 tw-no-underline tw-transition-colors hover:tw-text-iron-50"
         >
           View all
         </Link>
       </div>

-      {/* Grid */}
       <div className="tw-grid tw-grid-cols-1 tw-gap-4 md:tw-grid-cols-2 lg:tw-grid-cols-3 lg:tw-gap-5">
components/home/explore-waves/ExploreWaveCard.tsx (2)

32-32: Remove code comment.

Per coding guidelines, code should be self-explanatory without comments. The hook usage is clear from its name and parameters.

Suggested fix
-  // Fetch latest drop for message preview
   const { data: latestDrop, isLoading: isLoadingDrop } = useWaveLatestDrop(

46-46: Remove inline JSX comments.

Per coding guidelines, comments should be avoided. The JSX structure is self-explanatory. This applies to comments on lines 46, 66, 68, 73, and 80.

Suggested fix
-      {/* Image Area */}
       <div className="tw-relative tw-aspect-[16/10] tw-overflow-hidden">
components/home/explore-waves/useWaveLatestDrop.ts (2)

11-16: Consider defensive check for data.drops array.

If the API response structure changes or returns an unexpected shape, accessing data.drops[0] could throw. While the type indicates drops should always be an array, a defensive check would be safer.

Suggested fix
     queryFn: async () => {
       const data = await commonApiFetch<ApiWaveDropsFeed>({
         endpoint: `waves/${waveId}/drops`,
         params: { limit: "1" },
       });
-      return data.drops[0] ?? null;
+      return data.drops?.[0] ?? null;
     },

23-26: Remove JSDoc comment.

Per coding guidelines, code should be self-explanatory without comments. The function name and signature clearly convey the purpose.

Suggested fix
-/**
- * Extracts a text preview from drop parts.
- * Concatenates text content from all parts and truncates to maxLength.
- */
 export function extractDropPreview(
components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx (2)

110-118: Use <Image /> from next/image instead of <img>.

Per coding guidelines, replace <img> elements with the Next.js <Image /> component for optimized image loading.

Proposed fix
+import Image from "next/image";

// ...

                    {drop.author.pfp ? (
-                     <img
+                     <Image
                        className="tw-size-6 tw-flex-shrink-0 tw-rounded-lg tw-bg-iron-800 tw-object-contain tw-p-px tw-ring-1 tw-ring-inset tw-ring-iron-700"
                        src={drop.author.pfp}
                        alt={drop.author.handle ?? ""}
+                       width={24}
+                       height={24}
                      />
                    ) : (

62-91: Consider extracting repeated rank color logic.

The typeof drop.rank === "number" && drop.rank <= 3 check and getRankTextColor(drop.rank)?.replace("tw-text-", "").trim() pattern is repeated four times. Consider extracting to a computed value for maintainability.

Proposed simplification
const rankColor = typeof drop.rank === "number" && drop.rank <= 3
  ? getRankTextColor(drop.rank)?.replace("tw-text-", "").trim()
  : "#60606C";

// Then use rankColor in the style object
style={{
  border: "1px solid transparent",
  boxShadow: `inset 2px 0 0 ${rankColor},
              inset 0 1px 0 ${rankColor}20,
              inset -1px 0 0 ${rankColor}20,
              inset 0 -1px 0 ${rankColor}20`,
  transition: "box-shadow 0.2s ease, background-color 0.2s ease",
}}
components/waves/winners/WaveWinnersSmall.tsx (4)

91-101: Redundant convertApiDropToExtendedDrop calls.

The conversion function is called twice per winner—once for the drop prop and again inside onDropClick. Consider computing the extended drop once to avoid redundant work.

♻️ Suggested optimization
           <div className="tw-mt-3 tw-space-y-3">
-            {winners.map((winner) => (
-              <WaveWinnerItemSmall
-                key={winner.drop.id}
-                drop={convertApiDropToExtendedDrop(winner.drop)}
-                wave={wave}
-                rank={winner.place}
-                onDropClick={() =>
-                  onDropClick(convertApiDropToExtendedDrop(winner.drop))
-                }
-              />
-            ))}
+            {winners.map((winner) => {
+              const extendedDrop = convertApiDropToExtendedDrop(winner.drop);
+              return (
+                <WaveWinnerItemSmall
+                  key={winner.drop.id}
+                  drop={extendedDrop}
+                  wave={wave}
+                  rank={winner.place}
+                  onDropClick={() => onDropClick(extendedDrop)}
+                />
+              );
+            })}
           </div>

128-143: Same redundant conversion in multi-decision path.

Apply the same optimization here to avoid calling convertApiDropToExtendedDrop twice per winner.

♻️ Suggested optimization
         <div className="tw-space-y-3">
           {activeDecisionPoint &&
             decisionPoints
               .find((point) => point.id === activeDecisionPoint)
-              ?.winners.map((winner) => (
-                <WaveWinnerItemSmall
-                  key={winner.drop.id}
-                  drop={convertApiDropToExtendedDrop(winner.drop)}
-                  wave={wave}
-                  rank={winner.place}
-                  onDropClick={() =>
-                    onDropClick(convertApiDropToExtendedDrop(winner.drop))
-                  }
-                />
-              ))}
+              ?.winners.map((winner) => {
+                const extendedDrop = convertApiDropToExtendedDrop(winner.drop);
+                return (
+                  <WaveWinnerItemSmall
+                    key={winner.drop.id}
+                    drop={extendedDrop}
+                    wave={wave}
+                    rank={winner.place}
+                    onDropClick={() => onDropClick(extendedDrop)}
+                  />
+                );
+              })}
         </div>

116-117: Remove inline comments.

As per coding guidelines, code should be self-explanatory without comments.


127-127: Remove inline comment.

Same guideline applies here—remove the comment.

components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx (1)

84-89: Consider using <Image /> from next/image.

Per coding guidelines, prefer <Image /> over <img> for Next.js optimization benefits.

This appears to be pre-existing code (no ~ marker on line 85), so this may be out of scope for this PR. Verify if this change is intended to be addressed here or in a follow-up.

components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (1)

24-24: Unnecessary useMemo.

useMemo(() => drops, [drops]) provides no benefit—it returns the same reference that already changes when drops changes. Remove the wrapper and use drops directly.

♻️ Suggested fix
-  const memoizedDrops = useMemo(() => drops, [drops]);
+  // Use drops directly in the render

Then replace memoizedDrops with drops in the JSX below.

components/brain/right-sidebar/WaveContent.tsx (2)

48-55: Minor: Unnecessary fallback.

searchParams.toString() always returns a string (empty string if no params), so || "" is redundant.

♻️ Suggested simplification
  const onDropClick = useCallback(
    (drop: ExtendedDrop) => {
-      const params = new URLSearchParams(searchParams.toString() || "");
+      const params = new URLSearchParams(searchParams.toString());
      params.set("drop", drop.id);
      router.push(`${pathname}?${params.toString()}`, { scroll: false });
    },
    [router, pathname, searchParams]
  );

168-168: Remove inline comment.

Per coding guidelines, code should be self-explanatory without comments.

components/shared/WavesMessagesWrapper.tsx (1)

108-111: Consider moving error logging to an effect or removing it.

Logging during render executes on every render cycle while the error persists. While react-query's cached error state mitigates repeated logging, placing side effects in the render path is unconventional.

♻️ Option: Move to useEffect or rely on react-query's error boundary support
-  // Handle error state for drop loading
-  if (dropError && dropId) {
-    console.error("Failed to load drop:", dropError);
-  }
+  useEffect(() => {
+    if (dropError && dropId) {
+      console.error("Failed to load drop:", dropError);
+    }
+  }, [dropError, dropId]);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09e5e49 and 7d63b9d.

📒 Files selected for processing (29)
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/home/HomePageContent.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/explore-waves/index.ts
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/home/hero/HeroHeader.tsx
  • components/home/hero/index.ts
  • components/shared/WavesMessagesWrapper.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogDrop.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • docs/specs/2026-01-12-explore-waves-homepage-section.md
  • eslint.config.mjs
  • tsconfig.json
✅ Files skipped from review due to trivial changes (1)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogDrop.tsx
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or use useMemo instead.
Use useEffectEvent for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with "use cache" directive at the top of Server Components, routes, or functions. Configure cacheComponents: true in next.config.ts as needed.

**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
Use useEffectEvent when listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/index.ts
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/home/explore-waves/index.ts
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always add readonly before props in React components

**/*.{tsx,jsx}: Use internal links via <Link> component from Next.js instead of <a> tags
Replace <img> elements with <Image /> from next/image

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run lint to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running npm run lint
Do not add eslint-disable comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/index.ts
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/home/explore-waves/index.ts
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

**/*.{jsx,tsx}: Replace <img> elements with <Image /> from next/image to comply with Next.js ESLint rule @next/next/no-img-element.
Use <Link href="/path"> from Next.js for internal navigation instead of raw <a> tags to comply with @next/next/no-html-link-for-pages.

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/index.ts
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/home/explore-waves/index.ts
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript with React functional components and hooks

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/index.ts
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/home/explore-waves/index.ts
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{tsx,ts,jsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer direct named imports from React (useMemo, useRef, FC) over React. namespace usage

Files:

  • components/home/hero/HeroHeader.tsx
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/index.ts
  • components/home/HomePageContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
  • components/home/explore-waves/ExploreWaveCardSkeleton.tsx
  • components/brain/right-sidebar/BrainRightSidebar.tsx
  • components/brain/right-sidebar/WaveContent.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/brain/my-stream/MyStreamWave.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsx
  • components/home/explore-waves/index.ts
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins

Files:

  • components/home/hero/index.ts
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/home/explore-waves/index.ts
**/*.{test,spec}.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Run npm run test to execute all Jest tests and enforce ≥80% line coverage for files changed since main. Tests must pass and coverage threshold must be met before completing any task.

Enforce ≥ 80% line coverage for files changed since main by running npm run test

Files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
**/{__tests__,*.test.{tsx,ts}}

📄 CodeRabbit inference engine (AGENTS.md)

Place tests in __tests__/ directory or as ComponentName.test.tsx alongside the component

Files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
**/*.{test,spec}.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
🧠 Learnings (34)
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not include any comments in the code; it should be self-explanatory

Applied to files:

  • tsconfig.json
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Avoid double negatives in code; prefer explicit statements and use optional chaining (`?.`)

Applied to files:

  • tsconfig.json
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Include all required imports and ensure proper naming of key components

Applied to files:

  • tsconfig.json
  • components/home/hero/index.ts
  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Limit function cognitive complexity to 15 or less; extract deep ternaries (>3 levels)

Applied to files:

  • tsconfig.json
  • components/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsx
  • components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Use one import per module with ordering: external → internal → types, no duplicates

Applied to files:

  • tsconfig.json
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by running `npm run lint`

Applied to files:

  • tsconfig.json
  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : All tests must live in `__tests__` directory, mirroring source folder structure (`components`, `contexts`, `hooks`, `utils`)

Applied to files:

  • tsconfig.json
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Use realistic production-like data in tests

Applied to files:

  • tsconfig.json
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/{__tests__,*.test.{tsx,ts}} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` alongside the component

Applied to files:

  • tsconfig.json
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/__tests__/**/*.{test,spec}.{ts,tsx,js,jsx}|**/*.{test,spec}.{ts,tsx,js,jsx} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` files. Mock external dependencies and APIs in tests.

Applied to files:

  • tsconfig.json
  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use NextJS features that match the current version

Applied to files:

  • tsconfig.json
  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Write one behaviour per test with clear, descriptive test names

Applied to files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{test,spec}.{tsx,ts} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/*.{tsx,jsx},!**/__tests__/**,!**/__mocks__/** : Use semantic HTML (`<label>`, `<output>`) over ARIA attributes when possible

Applied to files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Test accessibility with keyboard navigation and screen reader compatibility

Applied to files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:37.305Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.305Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Follow Arrange – Act – Assert pattern in test structure

Applied to files:

  • __tests__/components/brain/right-sidebar/WaveContent.test.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Remove unnecessary Effects; if the Effect only derives state, compute during render instead

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to next.config.{ts,js,mjs} : Remove any `eslint` options from `next.config.*` files in Next.js 16

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Do not add `eslint-disable` comments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{js,ts,jsx,tsx} : Run `npm run lint` to ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to {eslint.config.js,next.config.ts} : Use ESLint CLI driven by `eslint-config-next` (flat config) instead of `next lint` (removed in Next.js 16)

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use explicit caching with `"use cache"` directive at the top of Server Components, routes, or functions. Configure `cacheComponents: true` in `next.config.ts` as needed.

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to next.config.{js,ts,mjs,mts} : With Next.js 16, `next lint` is removed. Use the ESLint CLI driven by `eslint-config-next` (flat config). Remove any `eslint` options from `next.config.*`.

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use TailwindCSS for styling in React components

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts,jsx,js} : Prefer direct named imports from React (`useMemo`, `useRef`, `FC`) over `React.` namespace usage

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,ts} : Use TypeScript with React functional components and hooks

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
  • components/waves/winners/WaveWinnersSmall.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{jsx,tsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of raw `<a>` tags to comply with `next/next/no-html-link-for-pages`.

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
📚 Learning: 2025-11-25T08:35:58.729Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-11-25T08:35:58.729Z
Learning: Applies to **/*.{tsx,jsx} : Use react-query for data fetching

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
  • components/home/explore-waves/useWaveLatestDrop.ts
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{tsx,jsx} : Use internal links via `<Link>` component from Next.js instead of `<a>` tags

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` for non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Move data fetching from client Effects to Server Components; mutations go through Server Actions (`'use server'`)

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to app/**/*.{ts,tsx} : Use `'use cache'` directive at the top of Server Components, routes, or functions to opt-in caching (Next.js 16+)

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
📚 Learning: 2025-12-30T14:32:19.360Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.360Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `useEffectEvent` when listening to external events but needing the latest props/state without re-running the Effect

Applied to files:

  • components/brain/right-sidebar/WaveContent.tsx
📚 Learning: 2025-12-30T14:31:53.006Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:53.006Z
Learning: Fix issues with modernization aligned to React 19.2, React Compiler, and Next.js 16 conventions. Do not add `// eslint-disable` comments unless explicitly instructed.

Applied to files:

  • components/waves/small-leaderboard/WaveSmallLeaderboard.tsx
🧬 Code graph analysis (12)
components/home/explore-waves/ExploreWaveCard.tsx (5)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
helpers/navigation.helpers.ts (1)
  • getWaveRoute (19-59)
helpers/Helpers.ts (2)
  • getRandomColorWithSeed (793-807)
  • getTimeAgoShort (606-640)
components/home/explore-waves/useWaveLatestDrop.ts (2)
  • useWaveLatestDrop (8-21)
  • extractDropPreview (27-45)
helpers/image.helpers.ts (1)
  • getScaledImageUri (17-45)
components/home/explore-waves/ExploreWavesSection.tsx (3)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
components/home/explore-waves/ExploreWaveCardSkeleton.tsx (1)
  • ExploreWaveCardSkeleton (3-25)
components/home/explore-waves/ExploreWaveCard.tsx (1)
  • ExploreWaveCard (16-96)
components/home/HomePageContent.tsx (6)
components/home/hero/HeroHeader.tsx (1)
  • HeroHeader (3-15)
components/home/carousel/SubmissionCarousel.tsx (1)
  • SubmissionCarousel (13-200)
components/home/now-minting/NowMintingSection.tsx (1)
  • NowMintingSection (7-40)
components/home/next-mint-leading/NextMintLeadingSection.tsx (1)
  • NextMintLeadingSection (12-81)
components/home/boosted/BoostedSection.tsx (1)
  • BoostedSection (11-65)
components/home/explore-waves/ExploreWavesSection.tsx (1)
  • ExploreWavesSection (12-71)
__tests__/components/brain/right-sidebar/WaveContent.test.tsx (1)
components/brain/right-sidebar/WaveContent.tsx (1)
  • WaveContent (34-174)
components/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsx (1)
components/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx (1)
  • DefaultWaveSmallLeaderboardDrop (11-29)
components/brain/right-sidebar/WaveContent.tsx (3)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (1)
  • WaveSmallLeaderboard (15-60)
components/waves/winners/WaveWinnersSmall.tsx (1)
  • WaveWinnersSmall (28-147)
components/home/explore-waves/useWaveLatestDrop.ts (3)
components/home/explore-waves/index.ts (2)
  • useWaveLatestDrop (4-4)
  • extractDropPreview (4-4)
generated/models/ApiWaveDropsFeed.ts (1)
  • ApiWaveDropsFeed (19-61)
generated/models/ApiDropWithoutWave.ts (1)
  • ApiDropWithoutWave (28-229)
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (2)
components/common/SystemAdjustmentPill.tsx (1)
  • SystemAdjustmentPill (1-11)
components/utils/tooltip/UserProfileTooltipWrapper.tsx (1)
  • UserProfileTooltipWrapper (12-34)
components/waves/small-leaderboard/WaveSmallLeaderboard.tsx (2)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
components/waves/winners/WaveWinnersSmall.tsx (5)
helpers/waves/drop.helpers.ts (2)
  • ExtendedDrop (16-20)
  • convertApiDropToExtendedDrop (110-123)
hooks/useWave.ts (1)
  • useWave (122-434)
hooks/waves/useWaveDecisions.ts (1)
  • useWaveDecisions (11-48)
components/waves/winners/WaveWinnerItemSmall.tsx (1)
  • WaveWinnerItemSmall (15-36)
components/waves/winners/WaveWinnersSmallDecisionSelector.tsx (1)
  • WaveWinnersSmallDecisionSelector (19-121)
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (19-24)
components/waves/winners/DefaultWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (19-24)
🪛 markdownlint-cli2 (0.18.1)
docs/specs/2026-01-12-explore-waves-homepage-section.md

142-142: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


154-154: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)

Comment thread components/home/explore-waves/ExploreWavesSection.tsx
Comment thread components/home/hero/HeroHeader.tsx Outdated
Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In `@components/home/next-mint-leading/LeadingCard.tsx`:
- Around line 34-85: The LeadingCard component shows interactive hover styles
but no navigation; either make the whole card actionable like the boosted drop
cards or remove the hover visuals. To fix, wrap the top-level container returned
by LeadingCard in a semantic interactive element (e.g., a <button> or Next.js
<Link>) or add an onClick/onKeyDown handler plus role="button" and tabIndex to
the outer div, and wire the handler to the same navigation target used by the
boosted drop card (use the same click handler or route logic), keeping the
existing hover classes (group-hover:tw-*) if you make it interactive; otherwise
remove the group-hover classes (e.g., group-hover:tw-scale-105,
group-hover:tw-border-white/10, group-hover:tw-text-white) from LeadingCard to
avoid misleading UI.
♻️ Duplicate comments (4)
components/home/now-minting/NowMintingSection.tsx (1)

8-8: Handle the error state from useNowMinting.

The hook returns an error property that is not destructured or handled. If the fetch fails, the component silently returns null instead of displaying an error UI.

🐛 Suggested fix
 export default function NowMintingSection() {
-  const { nft, isFetching } = useNowMinting();
+  const { nft, isFetching, error } = useNowMinting();

   if (isFetching && !nft) {
     return (
       // loading UI...
     );
   }

+  if (error) {
+    return null; // or render an error component
+  }
+
   if (!nft) {
     return null;
   }
components/home/carousel/CarouselActiveItemDetails.tsx (1)

36-57: Guard against undefined author.handle in Link href.

The condition author && doesn't protect against author.handle being undefined. If the handle is missing, the Link would navigate to /undefined.

🐛 Proposed fix
-      {author && (
+      {author?.handle && (
         <Link
           href={`/${author.handle}`}
components/home/boosted/BoostedDropCardHome.tsx (1)

71-76: Pass onContainerClick to enable card navigation on media clicks.

The DropListItemContentMedia component accepts an onContainerClick prop that should be wired to the parent's onClick handler. Without it, clicking on image media won't trigger card navigation because the image component intercepts clicks.

Proposed fix
              <DropListItemContentMedia
                media_mime_type={media.mime_type}
                media_url={media.url}
+               onContainerClick={onClick}
                imageScale={ImageScale.AUTOx450}
                imageObjectPosition="center"
              />
components/home/next-mint-leading/NextMintCard.tsx (1)

44-98: Card has interactive hover styling but lacks navigation.

The card displays hover effects (group-hover:tw-scale-105, group-hover:tw-border-white/10, group-hover:tw-text-white/80) that signal interactivity, but there's no <Link> wrapper or click handler. If users should navigate to the drop detail page when clicking, wrap the card in a Next.js <Link>. If the card is display-only, consider removing the hover effects to avoid misleading visual feedback.

🧹 Nitpick comments (5)
components/waves/drop/WaveDropVoteSummary.tsx (1)

80-107: Consider extending compact styling to remaining sections.

The compact prop currently only affects the rating/header section (lines 44-45, 55). The user vote section (line 80-97) and vote button have fixed sizing regardless of the compact flag.

If compact mode is intended for space-constrained layouts, you might want to apply smaller text/padding to these sections as well for visual consistency.

💡 Optional: Apply compact styling to user vote section
      {shouldShowUserVote && (
-        <div className="tw-px-4 tw-flex tw-items-baseline tw-gap-1 tw-border-l tw-border-solid tw-border-white/5 tw-border-y-0 tw-border-r-0">
+        <div className={`${headerPadding} tw-flex tw-items-baseline tw-gap-1 tw-border-l tw-border-solid tw-border-white/5 tw-border-y-0 tw-border-r-0`}>
components/home/carousel/SubmissionCarousel.tsx (2)

42-53: Consider extracting static constants outside the component.

The visual constants (cardGap, inactiveScale, slideTransition, inactiveFilter) are recreated on every render. Since they don't depend on props or state, extracting them to module scope would be a minor optimization.

Suggested extraction
+const CARD_GAP = 4;
+const INACTIVE_SCALE = 0.68;
+const SLIDE_TRANSITION =
+  "transform 0.45s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.45s cubic-bezier(0.25, 1, 0.5, 1)";
+const INACTIVE_FILTER = "grayscale(100%) blur(6px)";
+const SLIDE_WIDTH = "var(--carousel-card-width)";
+
 export default function SubmissionCarousel({
   onActiveDropChange,
 }: SubmissionCarouselProps) {
   // ...
-  const cardGap = 4;
-  const inactiveScale = 0.68;
-  const slideTransition =
-    "transform 0.45s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.45s cubic-bezier(0.25, 1, 0.5, 1)";
-  const inactiveFilter = "grayscale(100%) blur(6px)";
-  const slideWidth = "var(--carousel-card-width)";

102-102: Unused constant - consider removing or parameterizing.

showArrows is hardcoded to true and never conditionally changed. Either remove it and inline true, or convert it to a prop if conditional arrow display is intended in the future.

components/home/boosted/BoostedDropCardHome.tsx (1)

43-44: Consider removing JSX comment to maintain consistency.

A JSX comment remains on line 43. If the codebase follows a "no comments in code" guideline as mentioned in past reviews, this should be removed for consistency.

components/home/next-mint-leading/LeadingCard.tsx (1)

19-24: Consider extracting shared title/media extraction logic.

The title fallback chain (drop.title ?? metadata.find("title") ?? "Untitled") and media extraction (drop.parts[0]?.media[0]) patterns are duplicated across NextMintCard and LeadingCard. Consider extracting these to shared helpers in drop.helpers.ts for consistency and reduced duplication.

// Example helper in drop.helpers.ts
export function getDropTitle(drop: ApiDrop | ExtendedDrop): string {
  return drop.title ?? 
    drop.metadata.find((m) => m.data_key === "title")?.data_value ?? 
    "Untitled";
}

export function getDropMedia(drop: ApiDrop | ExtendedDrop) {
  return drop.parts[0]?.media[0];
}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88fa05c and b2c7ae6.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (21)
  • app/page.tsx
  • components/drops/view/item/content/media/DropListItemContentMedia.tsx
  • components/home/HomePageContent.tsx
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/HeroHeader.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/shared/WavesMessagesWrapper.tsx
  • components/waves/drop/MemesSingleWaveDropInfoPanel.tsx
  • components/waves/drop/WaveDropVoteSummary.tsx
💤 Files with no reviewable changes (1)
  • components/waves/drop/MemesSingleWaveDropInfoPanel.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
  • components/shared/WavesMessagesWrapper.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/now-minting/NowMintingDetails.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/hero/HeroHeader.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • components/home/HomePageContent.tsx
🧰 Additional context used
🧬 Code graph analysis (9)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
components/drops/view/item/content/media/DropListItemContentMediaGLB.tsx (1)
  • DropListItemContentMediaGLB (3-13)
components/home/boosted/BoostedDropCardHome.tsx (3)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-244)
helpers/image.helpers.ts (1)
  • getScaledImageUri (17-45)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (29-131)
components/home/next-mint-leading/NextMintLeadingSection.tsx (5)
contexts/SeizeSettingsContext.tsx (1)
  • useSeizeSettings (119-127)
hooks/waves/useWaveDecisions.ts (1)
  • useWaveDecisions (11-48)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (65-301)
components/home/next-mint-leading/NextMintCard.tsx (1)
  • NextMintCard (34-99)
components/home/next-mint-leading/LeadingCard.tsx (1)
  • LeadingCard (17-86)
components/home/next-mint-leading/LeadingCard.tsx (3)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (19-23)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-105)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (29-131)
components/home/explore-waves/ExploreWaveCard.tsx (5)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
helpers/navigation.helpers.ts (1)
  • getWaveRoute (19-59)
helpers/Helpers.ts (2)
  • getRandomColorWithSeed (793-807)
  • getTimeAgoShort (606-640)
components/home/explore-waves/useWaveLatestDrop.ts (1)
  • useWaveLatestDrop (8-21)
helpers/image.helpers.ts (1)
  • getScaledImageUri (17-45)
app/page.tsx (1)
components/home/HomePageContent.tsx (1)
  • HomePageContent (14-37)
components/home/now-minting/NowMintingSection.tsx (3)
hooks/useNowMinting.ts (1)
  • useNowMinting (11-22)
components/home/now-minting/NowMintingArtwork.tsx (1)
  • NowMintingArtwork (9-41)
components/home/now-minting/NowMintingDetails.tsx (1)
  • NowMintingDetails (15-47)
components/home/carousel/SubmissionCarousel.tsx (5)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (19-23)
contexts/SeizeSettingsContext.tsx (1)
  • useSeizeSettings (119-127)
hooks/useWaveDropsLeaderboard.ts (1)
  • useWaveDropsLeaderboard (65-301)
components/home/carousel/CarouselArrow.tsx (1)
  • CarouselArrow (16-44)
components/home/carousel/SubmissionArtworkCard.tsx (1)
  • SubmissionArtworkCard (12-46)
components/home/carousel/CarouselActiveItemDetails.tsx (1)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (19-23)
🔇 Additional comments (32)
components/home/now-minting/NowMintingSection.tsx (2)

10-19: LGTM!

The loading state logic correctly guards against showing loading UI when cached data is available (isFetching && !nft).


25-47: LGTM!

The grid layout and prop passing to NowMintingArtwork and NowMintingDetails are correctly wired based on the hook's return type.

components/home/carousel/CarouselActiveItemDetails.tsx (5)

1-10: LGTM!

Imports and interface definition are clean and appropriate. The readonly modifier on the prop and nullable type handling are good practices.


12-19: LGTM!

The hook is correctly called unconditionally before the early return, adhering to the Rules of Hooks.


21-28: LGTM!

Data extraction with appropriate fallbacks. The detailsId using drop.id ensures unique accessibility identifiers.


59-75: LGTM!

Good accessibility implementation with aria-expanded, aria-controls, and aria-hidden on the decorative icon. The toggle logic and animation are correctly implemented.


77-93: LGTM!

Nice use of the CSS grid rows technique for smooth height animation. The transition timing and overflow handling are well implemented.

components/waves/drop/WaveDropVoteSummary.tsx (4)

12-19: LGTM!

The interface is well-defined with all props marked as readonly. The compact boolean prop is a cleaner API than a variant enum for a simple two-state toggle.


21-31: LGTM!

The button styling constant is well-extracted, and the compact = false default ensures backward compatibility for existing callers.


32-40: LGTM!

The vote state logic is clear and the derived styling variables (ratingTextSize, headerPadding) cleanly handle the compact mode without over-complicating the JSX.


42-78: LGTM!

The container and header styling correctly applies the compact-derived variables. The conditional prediction display with tooltip is well-implemented.

app/page.tsx (3)

1-4: LGTM!

Clean import structure. The new HomePageContent import correctly replaces the previous data-fetching related imports.


6-12: Clean simplification - data fetching moved to client.

The Page component is now a thin server component wrapper that delegates to the client-side HomePageContent. This is a valid Next.js App Router pattern where:

  • Server component handles the route and layout structure
  • Client component manages interactive state and client-side data fetching

Since metadata generation remains server-side, SEO for social sharing and crawlers is preserved.


14-19: Appropriate sync signature for static metadata.

The generateMetadata function correctly returns static metadata without needing async. Since the og image and twitter card are constant values, no data fetching is required. The getAppMetadata helper is also synchronous, making this implementation appropriate.

components/home/carousel/SubmissionCarousel.tsx (5)

1-24: LGTM!

Clean imports with proper type annotations. The readonly modifier on the prop is a good TypeScript practice for component interfaces.


55-69: LGTM!

The deterministic shuffle using a hash function is a good approach for maintaining consistent ordering across re-renders. The hash |= 0 idiom correctly handles 32-bit integer conversion.


104-118: LGTM!

Clean early return pattern with appropriate loading and empty states. Returning null when there's no data prevents layout shifts.


156-168: LGTM!

Good Swiper configuration with centered slides and auto-sizing. Calling handleSlideChange in onSwiper correctly initializes the scroll state after the component mounts.


179-196: Good accessibility pattern with the button element.

Using a <button> for clickable slides with proper focus-visible styles enables keyboard navigation. The willChange optimization for adjacent slides is a good performance consideration.

One minor note: the z-index formula 10 - distance could produce negative values for carousels with many items, though the heavy blur and low opacity on inactive slides makes this unlikely to cause visible stacking issues.

components/home/boosted/BoostedDropCardHome.tsx (1)

18-35: LGTM!

The component logic is well-structured with appropriate memoization, safe optional chaining for data extraction, and proper text truncation handling.

components/drops/view/item/content/media/DropListItemContentMedia.tsx (2)

48-52: LGTM on state management.

The htmlActivated state and effect correctly handle the autoplay toggle, including resetting when media_url changes to ensure fresh content respects the autoplay setting.


34-45: LGTM on new props.

The new optional props (disableModal, disableAutoPlay, imageObjectPosition) are well-typed with appropriate defaults and correctly propagated to child media components.

components/home/next-mint-leading/NextMintLeadingSection.tsx (2)

14-40: LGTM on data fetching and state management.

The hook usage is correct with proper enabled flags to prevent unnecessary API calls when waveId is unavailable. The data extraction safely handles undefined values with optional chaining.


80-92: LGTM on rendering logic.

The conditional rendering properly handles loading and empty states. The responsive grid layout with lg:tw-grid-cols-3 provides appropriate visual hierarchy for the next mint and leading cards.

components/home/next-mint-leading/NextMintCard.tsx (1)

15-32: LGTM on timestamp formatting.

The formatDropTimestamp helper correctly validates the timestamp and uses Intl.DateTimeFormat for locale-aware formatting with appropriate fallback to null for invalid inputs.

components/home/next-mint-leading/LeadingCard.tsx (1)

17-32: LGTM on data handling and rank styling.

The data extraction with safe optional chaining and the rank-based color mapping (gold/silver/bronze) are well-implemented.

components/home/explore-waves/ExploreWaveCard.tsx (6)

1-14: LGTM!

Imports are well-organized and the interface properly uses readonly for immutability.


23-32: LGTM!

The color fallback logic handles missing author data gracefully. The gradient is only applied when there's no cover image, which is the correct behavior.


34-42: LGTM!

Good use of the enabled flag to conditionally fetch data only when drops exist, avoiding unnecessary API calls.


44-64: LGTM!

Good accessibility with aria-label, appropriate use of prefetch={false} to avoid prefetching many cards, and proper responsive image optimization with sizes prop.


107-129: LGTM!

Clean helper component with proper separation of loading, empty, and content states. The readonly modifier on props is a good practice for immutability.


71-86: Add tw-mt-2 to the "No drops yet" section for consistent spacing.

The "No drops yet" section (line 83) is missing the tw-mt-2 class present in the metadata section above (line 72), causing inconsistent vertical spacing between the two conditional states.

Regarding the timestamp unit: latest_drop_timestamp is consistently set using Date.now() (milliseconds) and getTimeAgoShort() expects milliseconds, so the timestamp is correctly formatted.

Likely an incorrect or invalid review comment.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread components/home/next-mint-leading/LeadingCard.tsx
Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: ragnep <ragneinfo@gmail.com>
Copy link
Copy Markdown

@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: 2

🤖 Fix all issues with AI agents
In `@components/drops/view/item/content/media/DropListItemContentMedia.tsx`:
- Around line 48-52: The effect that sets htmlActivated currently depends on
disableAutoPlay and media_url but misses media_mime_type, so when
media_mime_type changes to an HTML type without a media_url change the
htmlActivated state isn't updated; update the useEffect dependency array for the
effect that calls setHtmlActivated(!disableAutoPlay) in DropListItemContentMedia
(the useEffect that references htmlActivated/setHtmlActivated) to include
media_mime_type alongside disableAutoPlay and media_url so the effect reruns
when the MIME type changes.

In `@components/home/hero/CarouselHeader.tsx`:
- Around line 5-10: The hero component CarouselHeader currently contains
placeholder lorem ipsum copy in the section/span and paragraph; replace the
placeholder text within the CarouselHeader component (the span with class
"tw-m-0 tw-text-xl..." and the p with class "tw-mb-0 tw-mt-2 tw-text-base...")
with the final product marketing copy provided by PM/UX, ensuring tone/length
matches responsive styles and updates any aria-labels or alt text if provided
copy affects accessibility.
♻️ Duplicate comments (4)
components/home/now-minting/NowMintingSection.tsx (1)

7-50: Handle the useNowMinting error state.

The hook exposes error but the section ignores it and returns null, so failures are silent. Please render a simple error fallback (or existing error component) before returning null.

🐛 Suggested fix
-  const { nft, isFetching } = useNowMinting();
+  const { nft, isFetching, error } = useNowMinting();

   if (isFetching && !nft) {
     return (
       // loading UI...
     );
   }

+  if (error) {
+    return (
+      <section className="tw-px-4 tw-pb-32 tw-pt-16 md:tw-px-6 lg:tw-px-8">
+        <span className="tw-mb-4 tw-block tw-text-xl tw-font-semibold tw-tracking-tight tw-text-zinc-200 md:tw-mb-6 md:tw-text-2xl">
+          Latest Drop
+        </span>
+        <div className="tw-text-sm tw-text-iron-400">
+          Unable to load the latest drop.
+        </div>
+      </section>
+    );
+  }
components/home/explore-waves/ExploreWavesSection.tsx (1)

14-36: Log the fetch error before returning null.

The error path silently hides the section. Please log the error for debugging before returning null.

🐛 Suggested fix
   const {
     data: waves,
     isLoading,
     isError,
+    error,
   } = useQuery({

   // Hide section on error or if no waves
   if (isError) {
+    console.error("[ExploreWavesSection] Failed to fetch waves", error);
     return null;
   }
components/home/boosted/BoostedDropCardHome.tsx (1)

71-76: Pass onContainerClick to enable navigation on media clicks.

Image clicks in DropListItemContentMedia call event.stopPropagation(), preventing the parent button's onClick from firing. Wire the onContainerClick prop to ensure users can navigate when clicking on media content.

🐛 Proposed fix
               <DropListItemContentMedia
                 media_mime_type={media.mime_type}
                 media_url={media.url}
+                onContainerClick={onClick}
                 imageScale={ImageScale.AUTOx450}
                 imageObjectPosition="center"
               />
components/home/carousel/CarouselActiveItemVote.tsx (1)

17-24: Critical: Hooks called after early return violates Rules of Hooks.

The useState, useIsMobileScreen, and useDropInteractionRules hooks are called after the conditional return on lines 17-19. React requires all hooks to be called unconditionally in the same order on every render.

Since useDropInteractionRules expects ApiDrop (not nullable), the cleanest fix is to split into a wrapper component.

🐛 Proposed fix using wrapper pattern
 export default function CarouselActiveItemVote({
   drop,
 }: CarouselActiveItemVoteProps) {
   if (!drop) {
     return null;
   }
+  return <CarouselActiveItemVoteInner drop={drop} />;
+}

-  const [isVotingOpen, setIsVotingOpen] = useState(false);
-  const isMobileScreen = useIsMobileScreen();
-  const { canShowVote, isVotingEnded, isWinner } =
-    useDropInteractionRules(drop);
+function CarouselActiveItemVoteInner({
+  drop,
+}: {
+  readonly drop: ExtendedDrop;
+}) {
+  const [isVotingOpen, setIsVotingOpen] = useState(false);
+  const isMobileScreen = useIsMobileScreen();
+  const { canShowVote, isVotingEnded, isWinner } =
+    useDropInteractionRules(drop);

   return (
     <div className="tw-flex tw-items-center tw-justify-center tw-mt-4 tw-px-4 md:tw-px-6 lg:tw-px-8">
       ...
     </div>
   );
 }
🧹 Nitpick comments (5)
components/home/carousel/SubmissionCarousel.tsx (1)

102-102: Unused constant showArrows is always true.

This constant doesn't provide conditional logic. Consider removing it and the conditional checks, or extracting it to props if arrow visibility should be configurable.

♻️ Suggested simplification
-  const showArrows = true;
...
-  {showArrows && (
+  {(
     <div className="tw-mb-3 ...">

Or remove the conditionals entirely if arrows are always shown.

components/home/boosted/BoostedSection.tsx (1)

109-109: Remove JSX comment per repo guidelines.

Previous reviews flagged JSX comments in this file. This remaining comment should be removed for consistency.

♻️ Suggested fix
-        {/* Horizontal scroll container */}
         <div
           ref={scrollRef}
components/home/HomePageContent.tsx (1)

21-21: Consider extracting complex responsive classes.

The grid section has multiple complex media queries inline. While functional, extracting these to a CSS module or Tailwind @apply directive could improve readability and maintainability.

components/home/boosted/BoostedDropCardHome.tsx (1)

43-44: Remove JSX comments per repo guidelines.

Previous reviews flagged JSX comments in boosted components. These remaining comments should be removed for consistency.

♻️ Suggested fix
-         {/* Inner Highlight (Glass Edge) */}
         <div className="tw-absolute tw-inset-0 tw-rounded-xl tw-border ..." />
...
-              {/* Glow effect */}
               <div
                 className="tw-pointer-events-none tw-absolute tw-inset-0 ..."

Also applies to: 59-59

components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)

104-123: Prefer a real <button> for accessibility.
This avoids custom key handling and matches native semantics.

♿ Suggested refactor
-            <div
-              role="button"
-              tabIndex={0}
-              onClick={() => setHtmlActivated(true)}
-              onKeyDown={(event) => {
-                if (event.key === "Enter" || event.key === " ") {
-                  event.preventDefault();
-                  setHtmlActivated(true);
-                }
-              }}
-              className="tw-inline-flex tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-md tw-border tw-border-iron-700 tw-bg-iron-900/80 tw-px-3 tw-py-1.5 tw-text-xs tw-font-medium tw-text-iron-200 tw-transition hover:tw-bg-iron-800"
-            >
+            <button
+              type="button"
+              onClick={() => setHtmlActivated(true)}
+              className="tw-inline-flex tw-cursor-pointer tw-items-center tw-justify-center tw-rounded-md tw-border tw-border-iron-700 tw-bg-iron-900/80 tw-px-3 tw-py-1.5 tw-text-xs tw-font-medium tw-text-iron-200 tw-transition hover:tw-bg-iron-800"
+            >
               Tap to load
-            </div>
+            </button>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b2c7ae6 and d8bd5da.

📒 Files selected for processing (22)
  • components/drops/view/item/content/media/DropListItemContentMedia.tsx
  • components/home/HomePageContent.tsx
  • components/home/boosted/BoostedDropCardHome.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/carousel/CarouselActiveItemVote.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/hero/CarouselHeader.tsx
  • components/home/hero/HeroHeader.tsx
  • components/home/hero/index.ts
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/now-minting/NowMintingArtwork.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/waves/drop/WaveDropVoteSummary.tsx
🚧 Files skipped from review as they are similar to previous changes (10)
  • components/home/hero/index.ts
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/carousel/CarouselActiveItemDetails.tsx
  • components/home/now-minting/NowMintingHeader.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/hero/HeroHeader.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
🧰 Additional context used
🧬 Code graph analysis (8)
components/home/boosted/BoostedSection.tsx (2)
hooks/useBoostedDrops.ts (1)
  • useBoostedDrops (19-43)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-244)
components/home/now-minting/NowMintingSection.tsx (3)
hooks/useNowMinting.ts (1)
  • useNowMinting (11-22)
components/home/now-minting/NowMintingArtwork.tsx (1)
  • NowMintingArtwork (8-14)
components/home/now-minting/NowMintingDetails.tsx (1)
  • NowMintingDetails (15-47)
components/home/carousel/CarouselActiveItemVote.tsx (3)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (19-23)
hooks/drops/useDropInteractionRules.ts (1)
  • useDropInteractionRules (26-140)
components/waves/drop/WaveDropVoteSummary.tsx (1)
  • WaveDropVoteSummary (23-105)
components/home/boosted/BoostedDropCardHome.tsx (3)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-244)
helpers/image.helpers.ts (1)
  • getScaledImageUri (17-45)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (29-138)
components/waves/drop/WaveDropVoteSummary.tsx (1)
helpers/waves/waves.constants.ts (2)
  • WAVE_VOTING_LABELS (19-24)
  • WAVE_VOTE_STATS_LABELS (14-17)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
components/drops/view/item/content/media/DropListItemContentMediaGLB.tsx (1)
  • DropListItemContentMediaGLB (3-13)
components/home/explore-waves/ExploreWavesSection.tsx (3)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
components/home/explore-waves/ExploreWaveCardSkeleton.tsx (1)
  • ExploreWaveCardSkeleton (3-25)
components/home/explore-waves/ExploreWaveCard.tsx (1)
  • ExploreWaveCard (16-105)
components/home/now-minting/NowMintingArtwork.tsx (2)
entities/INFT.ts (1)
  • NFTWithMemesExtendedData (84-84)
components/nft-image/NFTImage.tsx (1)
  • NFTImage (21-57)
🪛 Biome (2.1.2)
components/home/carousel/CarouselActiveItemVote.tsx

[error] 21-21: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 22-22: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 24-24: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (17)
components/home/now-minting/NowMintingArtwork.tsx (1)

8-12: LGTM — clean and focused.

The component is simple, readable, and does exactly what it needs.

components/home/next-mint-leading/NextMintLeadingSection.tsx (1)

18-35: No action needed — hooks already default to arrays.

Both useWaveDecisions and useWaveDropsLeaderboard explicitly return arrays with proper defaults:

  • useWaveDecisions returns decisionPoints using ?? [] (line 39 of the hook)
  • useWaveDropsLeaderboard returns drops with an early if (!data?.pages) return [] guard (line 172 of the hook)

The code is safe from undefined access and does not require additional guards or fallbacks.

Likely an incorrect or invalid review comment.

components/home/carousel/SubmissionCarousel.tsx (3)

55-69: Deterministic shuffle implementation looks correct.

The hash-based shuffle using bitwise operations is a reasonable approach for stable ordering. The |= 0 coerces to 32-bit signed integer, preventing unbounded growth. The sort is stable across renders since it depends only on drop.id.


82-84: Effect dependency array is correct, but verify parent callback stability.

This effect fires whenever activeDrop or onActiveDropChange changes. Since the parent (HomePageContent) passes setActiveDrop directly (a stable React setter), this won't cause infinite loops. However, if a future refactor wraps the callback without useCallback, it could trigger repeated calls.


169-206: Carousel slides render with good accessibility patterns.

The slides include role="button", tabIndex={0}, and proper keyboard event handling for Enter/Space. The focus-visible ring provides visual feedback. Well implemented.

components/home/boosted/BoostedSection.tsx (3)

21-41: Scroll state management and cleanup are well implemented.

The updateScrollState callback correctly handles edge detection with epsilon tolerance. Event listeners are properly cleaned up, and the passive scroll listener is a good performance optimization.


43-48: Navigation URL construction looks correct.

The URL includes both wave and serialNo query parameters, aligning with the expected routing pattern for viewing a specific drop within a wave.


88-106: Scroll buttons have proper accessibility attributes.

Both buttons include aria-label, type="button", and appropriate disabled styling. The hover/active states provide good user feedback.

components/home/HomePageContent.tsx (1)

14-35: Component composition and state management are well structured.

The activeDrop state is lifted appropriately to coordinate between SubmissionCarousel and the voting/details components. Using setActiveDrop directly as the callback is correct since React state setters are stable.

components/home/boosted/BoostedDropCardHome.tsx (1)

18-122: Card component is well structured with appropriate memoization.

The memo() wrapper is appropriate here since the card receives stable props and benefits from referential equality checks. The truncation logic, URL detection, and conditional media/text rendering are implemented correctly.

components/waves/drop/WaveDropVoteSummary.tsx (3)

20-21: Clean refactor to inline styling.

The extraction of PRIMARY_BUTTON_CLASSES improves readability. If this button style is used elsewhere in the codebase, consider moving it to a shared constants file for reusability.


38-42: Consistent responsive styling applied.

The responsive gap (tw-gap-2 sm:tw-gap-3) and text sizing (tw-text-sm sm:tw-text-base) patterns are consistently applied throughout the component. The hover scale effect provides nice interaction feedback.


50-54: Rating display logic and styling preserved correctly.

The conditional coloring logic is correct—emerald indicates the rating will increase, rose indicates it will decrease. The component properly uses centralized constants (WAVE_VOTING_LABELS, WAVE_VOTE_STATS_LABELS) for label text, which aligns with the pattern in helpers/waves/waves.constants.ts.

Also applies to: 70-72, 77-91

components/drops/view/item/content/media/DropListItemContentMedia.tsx (4)

1-4: Client directive + hooks import look appropriate.


29-46: Props extension + defaults look good.


83-90: Image prop forwarding is solid.


93-98: Video autoplay toggle wiring looks good.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread components/drops/view/item/content/media/DropListItemContentMedia.tsx Outdated
Comment thread components/home/hero/CarouselHeader.tsx Outdated
simo6529 and others added 9 commits January 16, 2026 12:48
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: ragnep <ragneinfo@gmail.com>
Copy link
Copy Markdown

@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: 1

🤖 Fix all issues with AI agents
In `@components/home/next-mint-leading/NextMintCard.tsx`:
- Line 37: The line computing the media variable can throw if drop.parts[0]
exists but its media is null/undefined; update the expression that defines media
(currently "const media = drop.parts[0]?.media[0];") to use optional chaining on
the media array (e.g., access media with ?.[] ) so it safely resolves to
undefined when media is missing—locate the media declaration in NextMintCard
(the const media variable) and change it to use optional chaining on media.
♻️ Duplicate comments (2)
components/home/carousel/CarouselArrow.tsx (1)

39-42: Inconsistent Tailwind class prefix on shrink-0.

Line 41 uses shrink-0 without the tw- prefix while all other Tailwind classes use it. This may prevent the class from applying correctly.

Proposed fix
       <FontAwesomeIcon
         icon={faChevronLeft}
-        className={`tw-size-4 shrink-0 ${isLeft ? "" : "tw-rotate-180"}`}
+        className={`tw-size-4 tw-shrink-0 ${isLeft ? "" : "tw-rotate-180"}`}
       />
components/home/boosted/BoostedSection.tsx (1)

109-109: Remove JSX comment to align with “no comments in code” guideline.
Same issue as previously flagged; please delete the JSX comment.

✂️ Suggested change
-        {/* Horizontal scroll container */}
🧹 Nitpick comments (4)
components/home/next-mint-leading/LeadingCard.tsx (1)

26-31: Guard optional drop fields to avoid runtime crashes.

If drop.parts or drop.metadata can be undefined from the API, direct access will throw. Please confirm the API contract; if not guaranteed, use optional chaining/defaults.

♻️ Suggested defensive update
-  const media = drop.parts[0]?.media[0];
+  const media = drop.parts?.[0]?.media?.[0];
   const title =
     drop.title ??
-    drop.metadata.find((m) => m.data_key === "title")?.data_value ??
+    drop.metadata?.find((m) => m.data_key === "title")?.data_value ??
     "Untitled";
components/home/explore-waves/ExploreWaveCard.tsx (2)

25-33: Use distinct seeds for banner gradient fallback.

If both banner colors are missing, the same seed is used twice, so the gradient collapses to a flat color. Consider deriving two distinct seeds to preserve a gradient.

♻️ Possible refinement
-  const banner1 =
-    author.banner1_color ?? getRandomColorWithSeed(author.handle ?? "");
-  const banner2 =
-    author.banner2_color ?? getRandomColorWithSeed(author.handle ?? "");
+  const seed = author.handle ?? "";
+  const banner1 =
+    author.banner1_color ?? getRandomColorWithSeed(`${seed}-1`);
+  const banner2 =
+    author.banner2_color ?? getRandomColorWithSeed(`${seed}-2`);

109-124: Consider a small fallback when preview is unavailable.

When drops exist but preview extraction returns null, the row renders only the icon. A short placeholder text keeps the UI from looking empty.

🧩 Example fallback
-  if (!previewContent) {
-    return null;
-  }
+  if (!previewContent) {
+    return (
+      <span className="tw-text-xs tw-text-iron-500">No preview available</span>
+    );
+  }
hooks/useMintCountdownState.ts (1)

35-42: Avoid render-phase state updates when syncing to nftId.

Calling state setters during render triggers side effects that violate React's render purity. Move the reset into a useEffect dependency on nftId instead.

♻️ Suggested refactor
-import { useMemo, useState } from "react";
+import { useEffect, useMemo, useState } from "react";

   const [errorFromCallback, setErrorFromCallback] = useState(false);

-  // Reset error state when nftId changes (during render, not in effect)
-  const [prevNftId, setPrevNftId] = useState(nftId);
-  if (nftId !== prevNftId) {
-    setPrevNftId(nftId);
-    setErrorFromCallback(false);
-  }
+  useEffect(() => {
+    setErrorFromCallback(false);
+  }, [nftId]);
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 15de448 and f6fad7e.

📒 Files selected for processing (16)
  • app/page.tsx
  • components/drops/view/item/content/media/DropListItemContentMediaVideo.tsx
  • components/home/HomePageContent.tsx
  • components/home/boosted/BoostedSection.tsx
  • components/home/carousel/CarouselArrow.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/explore-waves/ExploreWaveCard.tsx
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/next-mint-leading/LeadingCard.tsx
  • components/home/next-mint-leading/NextMintCard.tsx
  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/now-minting/NowMintingCountdownActive.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • hooks/useMintCountdownState.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • components/home/explore-waves/ExploreWavesSection.tsx
  • components/home/next-mint-leading/NextMintLeadingSection.tsx
  • components/home/carousel/SubmissionCarousel.tsx
  • components/home/now-minting/NowMintingSection.tsx
  • components/home/now-minting/NowMintingDetailsAccordion.tsx
  • components/home/carousel/SubmissionArtworkCard.tsx
  • components/home/HomePageContent.tsx
  • components/drops/view/item/content/media/DropListItemContentMediaVideo.tsx
🧰 Additional context used
🧬 Code graph analysis (7)
components/home/boosted/BoostedSection.tsx (3)
components/home/boosted/index.ts (1)
  • BoostedSection (1-1)
hooks/useBoostedDrops.ts (1)
  • useBoostedDrops (19-43)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-244)
app/page.tsx (1)
components/home/HomePageContent.tsx (1)
  • HomePageContent (14-46)
components/home/next-mint-leading/NextMintCard.tsx (4)
generated/models/ApiDrop.ts (1)
  • ApiDrop (29-244)
components/home/next-mint-leading/index.ts (1)
  • NextMintCard (2-2)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-105)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (29-138)
components/home/now-minting/NowMintingCountdownActive.tsx (2)
hooks/useMintCountdownState.ts (1)
  • CountdownData (12-18)
utils/timeFormatters.ts (1)
  • formatCountdownVerbose (78-96)
hooks/useMintCountdownState.ts (2)
hooks/useManifoldClaim.ts (1)
  • useMemesManifoldClaim (237-245)
components/cookies/CookieConsentContext.tsx (1)
  • useCookieConsent (44-51)
components/home/explore-waves/ExploreWaveCard.tsx (8)
generated/models/ApiWave.ts (1)
  • ApiWave (28-180)
components/home/explore-waves/index.ts (2)
  • ExploreWaveCard (2-2)
  • useWaveLatestDrop (4-4)
helpers/navigation.helpers.ts (1)
  • getWaveRoute (19-59)
helpers/Helpers.ts (2)
  • getRandomColorWithSeed (793-807)
  • getTimeAgoShort (606-640)
components/home/explore-waves/useWaveLatestDrop.ts (1)
  • useWaveLatestDrop (10-23)
helpers/image.helpers.ts (1)
  • getScaledImageUri (17-45)
components/waves/drops/media-utils.ts (1)
  • ProcessedContent (73-76)
components/waves/drops/ContentDisplay.tsx (1)
  • ContentDisplay (15-50)
components/home/next-mint-leading/LeadingCard.tsx (4)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (19-23)
components/home/next-mint-leading/index.ts (1)
  • LeadingCard (1-1)
hooks/useDeviceInfo.ts (1)
  • useDeviceInfo (23-105)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (29-138)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
components/home/carousel/CarouselArrow.tsx (1)

1-45: Well-structured carousel arrow component.

The component follows coding guidelines by using FontAwesome icons, has proper accessibility with aria-label, and provides flexible placement options. The readonly props and clean conditional logic are good practices.

components/home/now-minting/NowMintingCountdownActive.tsx (3)

1-9: LGTM!

Clean imports with appropriate type usage. The readonly modifier on the props interface enforces immutability, which is good practice.


11-55: LGTM!

Well-structured component with clean conditional rendering. The spacer div maintaining consistent height when the mint button is hidden is a good UX pattern for layout stability.


57-91: LGTM!

Solid timer implementation:

  • Using setTimeout with second-boundary alignment (1000 - (now % 1000)) prevents drift and ensures smooth updates.
  • Proper cleanup prevents memory leaks.
  • memo wrapper avoids unnecessary re-renders.
  • Lazy state initializer is efficient.
components/home/next-mint-leading/NextMintCard.tsx (3)

16-33: LGTM!

The timestamp formatting function correctly validates the date and uses Intl.DateTimeFormat for locale-aware formatting. The fallback to null for invalid timestamps is handled gracefully in the rendering logic.


83-101: LGTM — navigation links properly implemented.

The title links to the drop detail page and the author links to the profile page. This addresses the interactivity concern from the previous review while allowing distinct navigation targets for different elements, which is better for UX than wrapping the entire card in a single link.


45-79: LGTM!

The card structure is well-organized with proper conditional rendering for media. The hover effects (group-hover:tw-scale-105, group-hover:tw-border-white/10) appropriately signal interactivity and are now backed by actual Links in the content section. The touch-device handling via disableAutoPlay and disableModal is a good UX consideration.

app/page.tsx (2)

14-18: Static metadata looks good.

Clean, deterministic metadata generation with getAppMetadata and BASE_ENDPOINT.


3-9: HomePageContent is properly configured as a client component. The "use client" directive is present at line 1 of components/home/HomePageContent.tsx, allowing the use of React hooks (useState, useRef, useCallback) in the component.

components/home/next-mint-leading/LeadingCard.tsx (1)

35-94: LGTM — clean layout and sensible touch gating.

Nice use of useDeviceInfo to disable autoplay/modal on touch devices, and the hierarchy reads well.

components/home/explore-waves/ExploreWaveCard.tsx (1)

36-38: No action needed—timestamp units are correct.

latest_drop_timestamp is already in milliseconds (as confirmed by the usage of Date.now() when updating the value in increaseWavesOverviewDropsCount.tsx), and getTimeAgoShort expects and correctly processes milliseconds. The implementation safely divides by 1000 internally to compute time differences, and the function signature explicitly documents the millisecond expectation. No unit normalization is required.

Likely an incorrect or invalid review comment.

hooks/useMintCountdownState.ts (1)

12-29: Clear, explicit state modeling.

The union type and CountdownData shape make UI branching straightforward and type-safe.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread components/home/next-mint-leading/NextMintCard.tsx
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

@simo6529 simo6529 merged commit da9195f into main Jan 16, 2026
7 checks passed
@simo6529 simo6529 deleted the index-redesign branch January 16, 2026 15:40
@coderabbitai coderabbitai Bot mentioned this pull request Mar 9, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants