Conversation
📝 WalkthroughWalkthroughExtracted 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
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (3)
🧰 Additional context used🧬 Code graph analysis (1)components/home/carousel/SubmissionArtworkCard.tsx (3)
⏰ 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)
🔇 Additional comments (1)
✏️ Tip: You can disable this entire section by setting 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. Comment |
There was a problem hiding this comment.
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
onClickhandler 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
onVoteprop: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
textas 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 unnecessaryawaitkeyword.The result of
fetchNextPage()is not used, so theawaitkeyword 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 auseMemo, which means the order will change whenever thedropsdependency 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-livefor the active item, andaria-currentfor 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
📒 Files selected for processing (15)
__tests__/hooks/useWaveDropsLeaderboard.extra.test.ts__tests__/hooks/useWaveDropsLeaderboard.test.tsapp/page.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/home/HomePageContent.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/waves/leaderboard/drops/WaveLeaderboardDrops.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxdocs/home-page-spec.mdhooks/useWaveDropsLeaderboard.tsstyles/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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 lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
hooks/useWaveDropsLeaderboard.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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) overReact.namespace usage
Files:
hooks/useWaveDropsLeaderboard.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/waves/leaderboard/drops/WaveLeaderboardDrops.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxapp/page.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/HomePageContent.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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 exportgenerateMetadatausing the helper functiongetAppMetadatafrom@/components/providers/metadatawith 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
generateMetadatausing thegetAppMetadatahelper for proper metadata
Files:
app/page.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run testto execute all Jest tests and enforce ≥80% line coverage for files changed sincemain. Tests must pass and coverage threshold must be met before completing any task.Enforce ≥ 80% line coverage for files changed since
mainby runningnpm 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 asComponentName.test.tsxalongside 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.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVotes.tsxcomponents/waves/leaderboard/gallery/WaveLeaderboardGallery.tsxcomponents/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.tsxcomponents/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
'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
useIntersectionObserverhook expects a synchronous callback with signature(state: boolean) => void, but the code passes an async function. Since async functions returnPromise<void>(notvoid), 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_atensures 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
connectedProfileHandlefrom 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
fetchNextPagecall, 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 withoutconnectedProfileHandle.hooks/useWaveDropsLeaderboard.ts (2)
180-180: LGTM! Query now runs independently of authentication state.Removing the
connectedProfileHandlecheck from theenabledcondition 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 includesrefetch.Adding
refetchto the dependency array ensures the effect properly responds to changes. Whilerefetchfrom 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
HomePageContentclient 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 thegetAppMetadatahelper.The synchronous
generateMetadatafunction properly uses thegetAppMetadatahelper 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
connectedProfileHandlecorrectly 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.lengthdiffers from the approach inWaveSmallLeaderboardItemContent(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 displayparts[0]anyway, this inconsistency could cause drops with media exclusively inparts[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 examinesdrop.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.tsxline 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
waveIdis unavailable, and uses theRATING_PREDICTIONsort to show top-rated submissions. This aligns with the updated hook signature that no longer requiresconnectedProfileHandle.
183-183: No action required — the current implementation is correct.The
SubmissionArtworkCardcomponent accepts an optionalonClickprop (marked with?), so omitting it is valid. The button wrapper properly handles click events via its ownonClick={scrollToIndex(index)}handler. PlacingonClickon 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'stw-cursor-pointerand hover styling (hover:tw-scale-[1.02]) provide visual feedback without requiring an explicitonClickprop.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
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
errorproperty (visible in the relevant snippet fromhooks/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
onErrorhandler 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: Addingrefetchto dependency array may cause unnecessary effect re-runs.While
refetchis used inside the effect, react-query'srefetchfunction identity can change on re-renders. Consider usinguseEffectEventto wrap the refetch logic, or verify that react-query guarantees stable identity forrefetch.Based on learnings,
useEffectEventis 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, ifmanifoldClaim.isErroris 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 extractingformatEthoutside the component.The
formatEthfunction 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.jsLinkrenders 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
useIdentityhook returnsisLoadingwhich is currently unused. While the placeholder div provides a fallback whenprofile?.pfpis 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
textorplaintextto 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 capscomponents/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
📒 Files selected for processing (26)
components/home/HomePageContent.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/now-minting/NowMintingArtwork.tsxcomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/home/now-minting/NowMintingCountdownError.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownLoading.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingHeader.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/index.tscomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxdocs/helpers/you-might-not-need-an-effect.mddocs/home-page/carousel.mddocs/home-page/now-minting.mdhooks/useCountdown.tshooks/useMintCountdownState.tshooks/useNowMinting.tshooks/useWaveDropsLeaderboard.tsutils/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxutils/timeFormatters.tscomponents/home/now-minting/index.tscomponents/home/now-minting/NowMintingDetailsAccordion.tsxhooks/useMintCountdownState.tscomponents/home/now-minting/NowMintingCountdownError.tsxhooks/useNowMinting.tscomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxhooks/useCountdown.tscomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsxhooks/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/now-minting/NowMintingCountdownLoading.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingCountdownError.tsxcomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/now-minting/NowMintingCountdownLoading.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxutils/timeFormatters.tscomponents/home/now-minting/index.tscomponents/home/now-minting/NowMintingDetailsAccordion.tsxhooks/useMintCountdownState.tscomponents/home/now-minting/NowMintingCountdownError.tsxhooks/useNowMinting.tscomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxhooks/useCountdown.tscomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsxhooks/useWaveDropsLeaderboard.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingCountdownError.tsxcomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/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.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxutils/timeFormatters.tscomponents/home/now-minting/index.tscomponents/home/now-minting/NowMintingDetailsAccordion.tsxhooks/useMintCountdownState.tscomponents/home/now-minting/NowMintingCountdownError.tsxhooks/useNowMinting.tscomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxhooks/useCountdown.tscomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsxhooks/useWaveDropsLeaderboard.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/home/now-minting/NowMintingCountdownLoading.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxutils/timeFormatters.tscomponents/home/now-minting/index.tscomponents/home/now-minting/NowMintingDetailsAccordion.tsxhooks/useMintCountdownState.tscomponents/home/now-minting/NowMintingCountdownError.tsxhooks/useNowMinting.tscomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxhooks/useCountdown.tscomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsxhooks/useWaveDropsLeaderboard.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/now-minting/NowMintingCountdownLoading.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/home/now-minting/NowMintingCountdownFinalized.tsxcomponents/home/now-minting/NowMintingCountdownSoldOut.tsxcomponents/home/now-minting/NowMintingDetails.tsxutils/timeFormatters.tscomponents/home/now-minting/index.tscomponents/home/now-minting/NowMintingDetailsAccordion.tsxhooks/useMintCountdownState.tscomponents/home/now-minting/NowMintingCountdownError.tsxhooks/useNowMinting.tscomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingHeader.tsxhooks/useCountdown.tscomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/ipfs/IPFSContext.tsxcomponents/react-query-wrapper/ReactQueryWrapper.tsxcomponents/home/now-minting/NowMintingArtwork.tsxhooks/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.tscomponents/home/now-minting/index.tshooks/useMintCountdownState.tshooks/useNowMinting.tshooks/useCountdown.tshooks/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.tsdocs/helpers/you-might-not-need-an-effect.mdhooks/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.mdhooks/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.mdhooks/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.mdhooks/useCountdown.tshooks/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.,
DropListItemContentMediafor 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
useNowMintinghook.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 casetimestamp === 0would 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/imageinstead 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 />fromnext/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
waveIdpresence rather thanconnectedProfileHandle, 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
sortandwaveIdexplicitly and derivessortDirectionfromsort, soqueryFnalways has current values when the effect re-runs. SincequeryKeyis 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
statusLabelduring 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.mdfile. It correctly resetserrorFromCallbackwhennftIdchanges without using an Effect, avoiding extra render cycles.
56-91: LGTM - Well-structured discriminated union state.The
useMemocorrectly 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
useReducerfor 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
MintCountdownStatevariants, and TypeScript will catch any missing cases. The delegation to specific subcomponents keeps this component focused on orchestration.
There was a problem hiding this comment.
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
MintCountdownStatevariants correctly. Adding adefaultcase with aneverassertion 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 importingFCdirectly instead of usingReact.FC.The import statement already uses direct imports for
useMemo, but the component declaration still usesReact.FC. For consistency with the coding guidelines, consider importingFCdirectly.♻️ 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 forfetchNextPage.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 checkif (targetTime === null) return 0;at line 26 is redundant. This function is only invoked after confirmingtargetTime !== nullat line 20, sotargetTimeis 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
📒 Files selected for processing (6)
components/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/now-minting/NowMintingCountdown.tsxcomponents/home/now-minting/NowMintingCountdownLoading.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxhooks/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxhooks/useCountdown.tscomponents/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/now-minting/NowMintingCountdown.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/now-minting/NowMintingCountdown.tsxhooks/useCountdown.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/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.tsxhooks/useCountdown.tscomponents/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.tsxhooks/useCountdown.tscomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/now-minting/NowMintingCountdown.tsxhooks/useCountdown.tscomponents/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.tscomponents/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.tscomponents/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
readonlymodifier 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
There was a problem hiding this comment.
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
setTimeoutbased 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 inuseCountdownAdaptive.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
| undefinedis 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
📒 Files selected for processing (4)
components/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxhooks/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxhooks/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxhooks/useCountdown.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/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.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxhooks/useCountdown.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxhooks/useCountdown.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/now-minting/NowMintingStatsItem.tsxhooks/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
readonlyprops and appropriate typing.
24-36: LGTM! Well-structured render logic.The grid layout correctly shows four stats, with
isLoadingonly 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.
There was a problem hiding this comment.
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 | FloorPlacing "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 | Floordocs/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:
- Add language specifiers to fenced code blocks at lines 13, 42, and 145 (e.g.,
```textor```bash)- 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-900For 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
NextMintCardandBoostedDropCard, this component has noonClickhandler. 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
📒 Files selected for processing (14)
components/home/HomePageContent.tsxcomponents/home/boosted/BoostedDropCard.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/boosted/index.tscomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/next-mint-leading/index.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/waves/winners/WaveWinnersSmall.tsxdocs/home-page/next-mint-and-leading.mdhooks/useBoostedDrops.tshooks/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/next-mint-leading/index.tshooks/useBoostedDrops.tscomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxhooks/waves/useWaveDecisions.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/next-mint-leading/index.tshooks/useBoostedDrops.tscomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxhooks/waves/useWaveDecisions.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/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.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/next-mint-leading/index.tshooks/useBoostedDrops.tscomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxhooks/waves/useWaveDecisions.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/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.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/next-mint-leading/index.tshooks/useBoostedDrops.tscomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxhooks/waves/useWaveDecisions.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/next-mint-leading/index.tshooks/useBoostedDrops.tscomponents/home/boosted/BoostedDropCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxhooks/waves/useWaveDecisions.tscomponents/home/now-minting/NowMintingStatsGrid.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/HomePageContent.tsxcomponents/waves/winners/WaveWinners.tsxcomponents/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.tshooks/useBoostedDrops.tshooks/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.tscomponents/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.tshooks/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. Thestatusproperty is required (not optional) in theManifoldClaiminterface and is always populated when the claim object is created. There is no edge case wheremanifoldClaimis truthy butstatusis undefined—when the hook returns a claim object,statusis guaranteed to be one of theManifoldClaimStatusenum values. The loading logicisStatusLoading = !manifoldClaimcorrectly 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
waveIdinstead of the full wave object reduces coupling and aligns with the updateduseWaveDecisionshook 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 fornullorundefined, 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: 60sandrefetchInterval: 30sensures 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
waveobject to justwaveIdsimplifies the hook's API surface. Theenabledprop now has full control, which places responsibility on callers to ensurewaveIdis 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 fornullorundefined, 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.idmatching the newuseWaveDecisionssignature.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
useCallbackforhandleDropClickis appropriate since it's passed to child components.components/home/boosted/BoostedDropCard.tsx (1)
26-29: Good accessibility pattern.Using a
<button>element withtype="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
readonlymodifiers as per coding guidelines.
There was a problem hiding this comment.
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
decisionPointsarray is recreated on every render (lines 47-58), which causes theuseEffect(lines 61-65) to run on every render even whenrawDecisionPointshasn't changed. This violates the principle of efficient dependency management.As per coding guidelines: Remove unnecessary Effects and use
useMemofor 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/orauthor.handle) may be nullable depending on the generated model; consider a fallback to avoid renderingundefined.Also applies to: 73-75
components/home/boosted/BoostedSection.tsx (1)
17-22: Build the navigation URL withURLSearchParams(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
📒 Files selected for processing (4)
components/home/boosted/BoostedDropCardHome.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/boosted/index.tscomponents/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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxcomponents/home/boosted/index.tscomponents/home/boosted/BoostedDropCardHome.tsxcomponents/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/boosted/BoostedSection.tsxcomponents/home/boosted/BoostedDropCardHome.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/boosted/BoostedSection.tsxcomponents/home/boosted/index.tscomponents/home/boosted/BoostedDropCardHome.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/home/boosted/BoostedDropCardHome.tsxcomponents/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.tsxcomponents/home/boosted/index.tscomponents/home/boosted/BoostedDropCardHome.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/home/boosted/BoostedSection.tsxcomponents/home/boosted/index.tscomponents/home/boosted/BoostedDropCardHome.tsxcomponents/waves/winners/WaveWinnersSmall.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/boosted/BoostedSection.tsxcomponents/home/boosted/index.tscomponents/home/boosted/BoostedDropCardHome.tsxcomponents/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.idinstead 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 ensurenpm run lintis clean for these new TSX files (per guidelines).
There was a problem hiding this comment.
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 toprimary_addresswhenhandleis undefined.The
hrefcorrectly falls back toprimary_address, but the displayed text on line 143 only showshandle. Ifhandleisundefined, 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 toprimary_addresswhenhandleis 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_addressforhrefandtitle, but Line 64 displays onlylog.invoker.handle. Whenhandleis 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?.handleis falsy, but Line 114 tries to renderlog.drop_author?.handle, which will always be empty/undefined. Should displayprimary_addressas 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 render0in the DOM when media array is empty.When
drop.parts[0]?.media.lengthis0, React will render the literal0in 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 ofdrop.rankinstead ofrankparameter.The function accepts
rankas a parameter but the condition checksdrop.rankfrom the outer scope. This makes therankparameter 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 validReadonlyURLSearchParamsobject, andtoString()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 sincesearchParams.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 />fromnext/image.Per coding guidelines, use
<Image />fromnext/imageinstead 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 />fromnext/image.Same issue as in
DefaultWaveWinnerDropSmall.tsx—use<Image />fromnext/imageper 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
textorplaintextfor 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 fordata.dropsarray.If the API response structure changes or returns an unexpected shape, accessing
data.drops[0]could throw. While the type indicatesdropsshould 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 />fromnext/imageinstead 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 <= 3check andgetRankTextColor(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: RedundantconvertApiDropToExtendedDropcalls.The conversion function is called twice per winner—once for the
dropprop and again insideonDropClick. 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
convertApiDropToExtendedDroptwice 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 />fromnext/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: UnnecessaryuseMemo.
useMemo(() => drops, [drops])provides no benefit—it returns the same reference that already changes whendropschanges. Remove the wrapper and usedropsdirectly.♻️ Suggested fix
- const memoizedDrops = useMemo(() => drops, [drops]); + // Use drops directly in the renderThen replace
memoizedDropswithdropsin 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
📒 Files selected for processing (29)
__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/brain/my-stream/MyStreamWave.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/home/HomePageContent.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/explore-waves/index.tscomponents/home/explore-waves/useWaveLatestDrop.tscomponents/home/hero/HeroHeader.tsxcomponents/home/hero/index.tscomponents/shared/WavesMessagesWrapper.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogDrop.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/waves/winners/DefaultWaveWinnerDropSmall.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/waves/winners/WaveWinnersSmall.tsxdocs/specs/2026-01-12-explore-waves-homepage-section.mdeslint.config.mjstsconfig.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 useuseMemoinstead.
UseuseEffectEventfor 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. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen 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.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/index.tscomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/home/explore-waves/index.tscomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/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 addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/home/hero/HeroHeader.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto 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 runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/home/hero/HeroHeader.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/index.tscomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/home/explore-waves/index.tscomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto 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.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/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.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/index.tscomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/home/explore-waves/index.tscomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/home/hero/HeroHeader.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/index.tscomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/home/explore-waves/index.tscomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/waves/winners/DefaultWaveWinnerDropSmall.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/home/hero/HeroHeader.tsxcomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/index.tscomponents/home/HomePageContent.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDefaultDrop.tsxcomponents/waves/small-leaderboard/DefaultWaveSmallLeaderboardDrop.tsx__tests__/components/brain/right-sidebar/WaveContent.test.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardDrop.tsxcomponents/home/explore-waves/ExploreWaveCardSkeleton.tsxcomponents/brain/right-sidebar/BrainRightSidebar.tsxcomponents/brain/right-sidebar/WaveContent.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/brain/my-stream/MyStreamWave.tsxcomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboard.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardTopThreeDrop.tsxcomponents/home/explore-waves/index.tscomponents/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLogs.tsxcomponents/waves/winners/WaveWinnersSmall.tsxcomponents/waves/small-leaderboard/WaveSmallLeaderboardItemContent.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/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.tscomponents/home/explore-waves/useWaveLatestDrop.tscomponents/home/explore-waves/index.ts
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run testto execute all Jest tests and enforce ≥80% line coverage for files changed sincemain. Tests must pass and coverage threshold must be met before completing any task.Enforce ≥ 80% line coverage for files changed since
mainby runningnpm 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 asComponentName.test.tsxalongside 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.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/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.jsoncomponents/home/hero/index.tseslint.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.jsoncomponents/waves/small-leaderboard/MemesWaveSmallLeaderboardDrop.tsxcomponents/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.jsoneslint.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.jsoneslint.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.tsxcomponents/waves/winners/MemesWaveWinnerDropSmall.tsxcomponents/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.tsxcomponents/home/explore-waves/useWaveLatestDrop.tscomponents/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.tsxcomponents/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.tsxcomponents/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)
There was a problem hiding this comment.
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 theerrorstate fromuseNowMinting.The hook returns an
errorproperty that is not destructured or handled. If the fetch fails, the component silently returnsnullinstead 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 undefinedauthor.handlein Link href.The condition
author &&doesn't protect againstauthor.handlebeingundefined. 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: PassonContainerClickto enable card navigation on media clicks.The
DropListItemContentMediacomponent accepts anonContainerClickprop that should be wired to the parent'sonClickhandler. 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 extendingcompactstyling to remaining sections.The
compactprop 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 thecompactflag.If
compactmode 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.
showArrowsis hardcoded totrueand never conditionally changed. Either remove it and inlinetrue, 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 acrossNextMintCardandLeadingCard. Consider extracting these to shared helpers indrop.helpers.tsfor 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
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (21)
app/page.tsxcomponents/drops/view/item/content/media/DropListItemContentMedia.tsxcomponents/home/HomePageContent.tsxcomponents/home/boosted/BoostedDropCardHome.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/HeroHeader.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/now-minting/NowMintingArtwork.tsxcomponents/home/now-minting/NowMintingDetails.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/shared/WavesMessagesWrapper.tsxcomponents/waves/drop/MemesSingleWaveDropInfoPanel.tsxcomponents/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
NowMintingArtworkandNowMintingDetailsare 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
detailsIdusingdrop.idensures unique accessibility identifiers.
59-75: LGTM!Good accessibility implementation with
aria-expanded,aria-controls, andaria-hiddenon 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. Thecompactboolean 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 = falsedefault 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
HomePageContentimport 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
generateMetadatafunction correctly returns static metadata without needingasync. Since the og image and twitter card are constant values, no data fetching is required. ThegetAppMetadatahelper is also synchronous, making this implementation appropriate.components/home/carousel/SubmissionCarousel.tsx (5)
1-24: LGTM!Clean imports with proper type annotations. The
readonlymodifier 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 |= 0idiom correctly handles 32-bit integer conversion.
104-118: LGTM!Clean early return pattern with appropriate loading and empty states. Returning
nullwhen there's no data prevents layout shifts.
156-168: LGTM!Good Swiper configuration with centered slides and auto-sizing. Calling
handleSlideChangeinonSwipercorrectly initializes the scroll state after the component mounts.
179-196: Good accessibility pattern with the button element.Using a
<button>for clickable slides with properfocus-visiblestyles enables keyboard navigation. ThewillChangeoptimization for adjacent slides is a good performance consideration.One minor note: the z-index formula
10 - distancecould 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
htmlActivatedstate and effect correctly handle the autoplay toggle, including resetting whenmedia_urlchanges 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
enabledflags to prevent unnecessary API calls whenwaveIdis 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-3provides 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
formatDropTimestamphelper correctly validates the timestamp and usesIntl.DateTimeFormatfor locale-aware formatting with appropriate fallback tonullfor 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
readonlyfor 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
enabledflag to conditionally fetch data only when drops exist, avoiding unnecessary API calls.
44-64: LGTM!Good accessibility with
aria-label, appropriate use ofprefetch={false}to avoid prefetching many cards, and proper responsive image optimization withsizesprop.
107-129: LGTM!Clean helper component with proper separation of loading, empty, and content states. The
readonlymodifier on props is a good practice for immutability.
71-86: Addtw-mt-2to the "No drops yet" section for consistent spacing.The "No drops yet" section (line 83) is missing the
tw-mt-2class present in the metadata section above (line 72), causing inconsistent vertical spacing between the two conditional states.Regarding the timestamp unit:
latest_drop_timestampis consistently set usingDate.now()(milliseconds) andgetTimeAgoShort()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.
There was a problem hiding this comment.
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 theuseNowMintingerror state.The hook exposes
errorbut the section ignores it and returnsnull, so failures are silent. Please render a simple error fallback (or existing error component) before returningnull.🐛 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: PassonContainerClickto enable navigation on media clicks.Image clicks in
DropListItemContentMediacallevent.stopPropagation(), preventing the parent button'sonClickfrom firing. Wire theonContainerClickprop 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, anduseDropInteractionRuleshooks 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
useDropInteractionRulesexpectsApiDrop(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 constantshowArrowsis alwaystrue.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
@applydirective 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
📒 Files selected for processing (22)
components/drops/view/item/content/media/DropListItemContentMedia.tsxcomponents/home/HomePageContent.tsxcomponents/home/boosted/BoostedDropCardHome.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/carousel/CarouselActiveItemDetails.tsxcomponents/home/carousel/CarouselActiveItemVote.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/hero/CarouselHeader.tsxcomponents/home/hero/HeroHeader.tsxcomponents/home/hero/index.tscomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/now-minting/NowMintingArtwork.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingHeader.tsxcomponents/home/now-minting/NowMintingSection.tsxcomponents/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
useWaveDecisionsanduseWaveDropsLeaderboardexplicitly return arrays with proper defaults:
useWaveDecisionsreturnsdecisionPointsusing?? [](line 39 of the hook)useWaveDropsLeaderboardreturnsdropswith an earlyif (!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
|= 0coerces to 32-bit signed integer, preventing unbounded growth. The sort is stable across renders since it depends only ondrop.id.
82-84: Effect dependency array is correct, but verify parent callback stability.This effect fires whenever
activeDroporonActiveDropChangechanges. Since the parent (HomePageContent) passessetActiveDropdirectly (a stable React setter), this won't cause infinite loops. However, if a future refactor wraps the callback withoutuseCallback, 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
updateScrollStatecallback 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
waveandserialNoquery 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
activeDropstate is lifted appropriately to coordinate betweenSubmissionCarouseland the voting/details components. UsingsetActiveDropdirectly 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_CLASSESimproves 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 inhelpers/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.
There was a problem hiding this comment.
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 onshrink-0.Line 41 uses
shrink-0without thetw-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.partsordrop.metadatacan beundefinedfrom 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 tonftId.Calling state setters during render triggers side effects that violate React's render purity. Move the reset into a
useEffectdependency onnftIdinstead.♻️ 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
📒 Files selected for processing (16)
app/page.tsxcomponents/drops/view/item/content/media/DropListItemContentMediaVideo.tsxcomponents/home/HomePageContent.tsxcomponents/home/boosted/BoostedSection.tsxcomponents/home/carousel/CarouselArrow.tsxcomponents/home/carousel/SubmissionArtworkCard.tsxcomponents/home/carousel/SubmissionCarousel.tsxcomponents/home/explore-waves/ExploreWaveCard.tsxcomponents/home/explore-waves/ExploreWavesSection.tsxcomponents/home/next-mint-leading/LeadingCard.tsxcomponents/home/next-mint-leading/NextMintCard.tsxcomponents/home/next-mint-leading/NextMintLeadingSection.tsxcomponents/home/now-minting/NowMintingCountdownActive.tsxcomponents/home/now-minting/NowMintingDetailsAccordion.tsxcomponents/home/now-minting/NowMintingSection.tsxhooks/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
readonlymodifier 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
setTimeoutwith second-boundary alignment (1000 - (now % 1000)) prevents drift and ensures smooth updates.- Proper cleanup prevents memory leaks.
memowrapper 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.DateTimeFormatfor locale-aware formatting. The fallback tonullfor 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 viadisableAutoPlayanddisableModalis a good UX consideration.app/page.tsx (2)
14-18: Static metadata looks good.Clean, deterministic metadata generation with
getAppMetadataandBASE_ENDPOINT.
3-9: HomePageContent is properly configured as a client component. The"use client"directive is present at line 1 ofcomponents/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
useDeviceInfoto 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_timestampis already in milliseconds (as confirmed by the usage ofDate.now()when updating the value inincreaseWavesOverviewDropsCount.tsx), andgetTimeAgoShortexpects 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
CountdownDatashape make UI branching straightforward and type-safe.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
|



Summary by CodeRabbit
New Features
Improvements
Refactor
Documentation
Tests
✏️ Tip: You can customize this high-level summary in your review settings.