Skip to content

Leaderboard card list view touch-ups#1639

Merged
ragnep merged 6 commits intomainfrom
leaderboard-card-list-view
Dec 10, 2025
Merged

Leaderboard card list view touch-ups#1639
ragnep merged 6 commits intomainfrom
leaderboard-card-list-view

Conversation

@ragnep
Copy link
Copy Markdown
Contributor

@ragnep ragnep commented Dec 10, 2025

Summary by CodeRabbit

  • New Features

    • Dynamic top-voter avatar stacks with profile links and per-voter tooltips; formatted voter totals
    • Clickable artist badge to open submission preview; responsive "Your vote" badge on larger viewports
  • Style

    • Refined typography, spacing, borders, shadows, avatar sizing, and artwork/card layouts across leaderboards and drops
    • Updated tooltip visuals/positioning and toned-down vote button labels ("Vote" / "Voted")
  • Tests

    • Updated snapshot/selectors to match revised class names and visual changes

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

Signed-off-by: ragnep <ragneinfo@gmail.com>
Signed-off-by: ragnep <ragneinfo@gmail.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 10, 2025

Walkthrough

Widespread presentational and layout updates across voting, meme/drop, wave, and winner components: avatar rendering/styling and tooltip usage standardized, typography/spacing adjusted, some props added (e.g., dropId, wave, onDropClick), rank/badge styling consolidated, and tests updated to match new class names. No significant control-flow changes.

Changes

Cohort / File(s) Summary
Voter avatars & tooltips
components/brain/my-stream/votes/MyStreamWaveMyVote.tsx, components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx, components/memes/drops/MemeDropVoteStats.tsx, components/waves/drops/WaveDropRatings.tsx, components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx, components/waves/winners/drops/header/WaveWinnersDropVoters.tsx, components/memes/drops/MemesLeaderboardDropVoteSummary.tsx, components/memes/drops/MemesLeaderboardDrop.tsx, components/waves/drops/ArtistWinningArtworksContent.tsx, components/waves/drops/ArtistActiveSubmissionContent.tsx
Reworked avatar rendering (size, border, container), wrapped avatars with profile links, added per-voter Tooltips, replaced rater-count blocks with compact avatar stacks plus formatted total counts (uses formatNumberWithCommas).
Leaderboard / meme layout & typography
components/memes/drops/MemesLeaderboardDrop.tsx, components/memes/drops/MemesLeaderboardDropCard.tsx, components/memes/drops/MemesLeaderboardDropHeader.tsx, components/memes/drops/MemesLeaderboardDropDescription.tsx, components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
Reflowed header/title/description/footer into discrete blocks, updated typography, artwork background behavior, top‑3 border color tokens, and artist-info layout (passes onBadgeClick).
Traits & trait tooltips
components/memes/drops/MemeDropTrait.tsx, components/memes/drops/MemeDropTraits.tsx
Added optional dropId?: string, compute/use tooltipId (prefers dropId when present), switched to bordered card layout, centralized tooltip styling, and pass dropId when rendering traits.
Winner/badge and rank styling
components/memes/drops/MemeWinnerDrop.tsx, components/waves/drops/winner/WinnerDropBadge.tsx, components/waves/winners/drops/DefaultWaveWinnerDrop.tsx, components/waves/winners/drops/MemesWaveWinnerDrop.tsx, components/waves/winners/drops/header/WaveWinnersDropHeader.tsx, components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx, components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
Replaced inline color/shadow with Tailwind class-based colorClasses, adjusted shadow opacities, moved badge rendering in some places, and reorganized header/badge layouts to column flows.
Wave drop vote UI & inputs
components/waves/drop/SingleWaveDropVoteContent.tsx, components/waves/drop/SingleWaveDropVoteInput.tsx, components/waves/drop/SingleWaveDropVoteSubmit.tsx, components/drops/view/utils/DropVoteProgressing.tsx, components/waves/drop/SingleWaveDropVotes.tsx, components/waves/drop/SingleWaveDropVoters.tsx, components/waves/drop/SingleWaveDropLogs.tsx
Visual tweaks only: updated backgrounds/borders/colors, reduced corner radii (xl→lg), restyled progress badge (border, mono font, fixed arrow color), simplified vote labels ("Vote" / "Voted"), and tightened rating typography.
Profile / CIC / avatar containers
components/user/utils/UserCICAndLevel.tsx, components/waves/drop/SingleWaveDropAuthor.tsx, components/waves/drops/WaveDropAuthorPfp.tsx, components/waves/drops/time/WaveDropTime.tsx, components/waves/drops/SubmissionPosition.tsx
Enlarged avatar containers, reworked level/CIC badge to bordered solid style, adjusted positioning/typography, and consolidated rank color classes.
Buttons, actions & tooltips
components/waves/drops/WaveDropActionsOpen.tsx, components/waves/drops/WaveDropActionsOptions.tsx, components/waves/leaderboard/header/WaveleaderboardHeader.tsx, components/waves/leaderboard/header/WaveleaderboardSort.tsx, components/voting/VotingModalButton.tsx
Updated button sizes/rounding and active/inactive classes, SVG size reductions, standardized tooltip offset/opacity and inline style blocks; added `variant?: "default"
Winning artworks / artist submissions
components/waves/drops/ArtistWinningArtworksContent.tsx, components/waves/drops/ArtistActiveSubmissionContent.tsx, components/waves/drops/ArtistPreviewModalTabs.tsx
Converted cards to dark bordered panels with aspect-square media containers, added eye-overlay on hover, consolidated metadata area, and adjusted active tab bg color.
Traits count / metadata display
components/waves/drop/SingleWaveDropTraits.tsx, components/memes/drops/MemesLeaderboardDropDescription.tsx, components/waves/drop/SingleWaveDropVoteContent.tsx, components/memes/drops/MemeDropTrait.tsx
Metadata card styling tightened (darker bg, border, padding), labels uppercase/bold with tighter tracking, initial visible traits reduced from 4→2 with show‑all toggle, and description text size/color adjusted.
Tests updated
__tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx, __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx, __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
Updated test selectors and expected class strings to match new Tailwind tokens, padding/bg adjustments, and active-state class changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing extra attention:
    • Consistency of Tooltip id/offset/opacity and inline style usage across components.
    • Prop additions and propagation: dropId in trait components; wave and onDropClick in winners.
    • Avatar sizing, Next.js Image vs <img> fallbacks and border/placeholder consistency.
    • Rank/badge color and shadow token parity for top-3 styles and test expectations.

Possibly related PRs

Suggested reviewers

  • simo6529
  • analyticsflowee

Poem

🐰 I hopped through props and Tailwind leaves,
Polished badges, avatars, and little tooltips, please.
Colors tidy, ranks now beam,
I munched some classes — what a dream! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main focus of the changeset: visual and layout refinements to the leaderboard card list view, addressing styling, spacing, typography, and component organization across multiple related components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch leaderboard-card-list-view

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

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (6)
components/waves/drop/SingleWaveDropVoters.tsx (1)

79-79: Border radius mismatch between button and content container.

The button uses tw-rounded-t-lg when open (line 41), but the content container below uses tw-rounded-b-xl (line 79). This creates a visual inconsistency at their join—the bottom corners are more rounded than the top corners. For a cohesive appearance aligned with the styling touch-ups in this PR, the border radii should match.

Apply this diff to align the bottom border radius:

-            className="tw-overflow-hidden tw-ring-1 tw-ring-iron-700 tw-rounded-b-xl tw-bg-iron-900">
+            className="tw-overflow-hidden tw-ring-1 tw-ring-iron-700 tw-rounded-b-lg tw-bg-iron-900">
components/waves/drop/SingleWaveDropAuthor.tsx (1)

18-30: Replace avatar <img> with <Image /> from next/image

The avatar uses a plain <img> tag, which violates the @next/next/no-img-element ESLint rule. Migrate to next/image with the existing sizing and ring styles preserved. The conditional rendering pattern (showing the image when drop.author.pfp exists, otherwise showing the fallback div) remains compatible with the Image component.

components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)

113-117: Replace <img> with <Image /> from next/image.

Per coding guidelines, <img> elements should be replaced with <Image /> from next/image to satisfy the @next/next/no-img-element ESLint rule and benefit from automatic image optimization.

+import Image from "next/image";
-              <img
-                src={drop.author.pfp}
-                alt="Profile"
-                className="tw-h-full tw-w-full tw-object-contain tw-bg-iron-800"
-              />
+              <Image
+                src={drop.author.pfp}
+                alt="Profile"
+                fill
+                sizes="24px"
+                className="tw-object-contain tw-bg-iron-800"
+              />
components/waves/drops/WaveDropRatings.tsx (1)

32-40: Replace <img> with Next.js <Image> component.

The <img> element should be replaced with <Image> from next/image to satisfy the @next/next/no-img-element ESLint rule.

Apply this diff:

+import Image from "next/image";

  {rater.profile.pfp ? (
-   <img
-     src={getScaledImageUri(
-       rater.profile.pfp,
-       ImageScale.W_AUTO_H_50
-     )}
-     alt={`${rater.profile.handle}'s avatar`}
-     className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
-     data-tooltip-id={`rater-${rater.profile.id}`}
-   />
+   <div className="tw-relative tw-w-6 tw-h-6">
+     <Image
+       src={getScaledImageUri(
+         rater.profile.pfp,
+         ImageScale.W_AUTO_H_50
+       )}
+       alt={`${rater.profile.handle}'s avatar`}
+       className="tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
+       data-tooltip-id={`rater-${rater.profile.id}`}
+       fill
+       sizes="24px"
+     />
+   </div>
  ) : (

As per coding guidelines, replace <img> elements with <Image /> from next/image.

components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx (1)

17-21: Replace <img> with Next.js <Image> component.

Using <img> elements violates the @next/next/no-img-element ESLint rule.

As per coding guidelines, replace with Next.js <Image> component:

+import Image from "next/image";

 export default function WaveWinnersDropHeaderAuthorPfp({
   winner,
 }: WaveWinnersDropHeaderAuthorPfpProps) {
   return (
     <div className="tw-h-12 tw-w-12 tw-bg-iron-900 tw-relative tw-flex-shrink-0 tw-rounded-lg">
       {winner.drop.author.pfp ? (
         <div className="tw-rounded-lg tw-h-full tw-w-full">
           <div className="tw-h-full tw-w-full tw-max-w-full tw-rounded-lg tw-overflow-hidden tw-bg-iron-900 tw-ring-1 tw-ring-white/10">
             <div className="tw-h-full tw-text-center tw-flex tw-items-center tw-justify-center tw-rounded-lg tw-overflow-hidden">
-              <img
+              <Image
                 src={winner.drop.author.pfp}
                 alt="Profile picture"
-                className="tw-bg-transparent tw-max-w-full tw-max-h-full tw-h-auto tw-w-auto tw-mx-auto tw-object-contain"
+                fill
+                className="tw-object-contain"
               />
             </div>
components/memes/drops/MemesLeaderboardDropVoteSummary.tsx (1)

1-111: Replace <img> with Next <Image> for voter avatars (and optionally trim comments)

This layout and logic look good, but the plain <img> will violate @next/next/no-img-element and the project guideline to use next/image in TSX. You can fix this by importing Image and swapping the avatar element:

-import React from "react";
-import { formatNumberWithCommas } from "@/helpers/Helpers";
-import Link from "next/link";
+import React from "react";
+import { formatNumberWithCommas } from "@/helpers/Helpers";
+import Link from "next/link";
+import Image from "next/image";
@@
-                  {voter.profile.pfp ? (
-                    <img
-                      className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
-                      src={voter.profile.pfp}
-                      alt="Recent voter"
-                    />
-                  ) : (
+                  {voter.profile.pfp ? (
+                    <Image
+                      className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
+                      src={voter.profile.pfp}
+                      alt={`${voter.profile.handle}'s avatar`}
+                      width={24}
+                      height={24}
+                    />
+                  ) : (

Optionally, to align with the “no comments in TSX” guideline, you could also remove the inline JSX comments and rely on the structure and naming to document intent.

♻️ Duplicate comments (1)
components/waves/drops/WaveDropActionsOpen.tsx (1)

56-68: Duplicate tooltip styling—see previous comment.

This tooltip styling is identical to the one in WaveDropActionsOptions.tsx (lines 47-59). Please refer to the refactoring suggestion in that file to extract this to a shared constant.

🧹 Nitpick comments (15)
components/waves/drop/SingleWaveDropLogs.tsx (1)

38-42: Check radius token consistency between header button and logs container

The open state now uses tw-rounded-t-lg for the button (Line 41) while the logs container below still uses tw-rounded-b-xl (Line 78). This creates a mixed-radius card (lg on top, xl on bottom). If the design system aims for uniform corner radii per surface, consider aligning these (e.g., both *-lg or both *-xl), or confirm that the asymmetric look is intentional.

components/waves/drops/WaveDropActionsOptions.tsx (1)

47-59: Extract duplicate tooltip styling to a shared constant.

The tooltip styling defined here (lines 47-58) is identical to the styling in WaveDropActionsOpen.tsx (lines 56-67). This duplication creates a maintenance burden—any future tooltip style changes would need to be updated in multiple locations.

Consider extracting the common tooltip style object to a shared constant, utility file, or custom tooltip component.

Example approach:

// helpers/tooltip.helpers.ts or constants/tooltip.constants.ts
export const COMMON_TOOLTIP_STYLE = {
  padding: "4px 8px",
  background: "#37373E",
  color: "white",
  fontSize: "13px",
  fontWeight: 500,
  borderRadius: "6px",
  boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
  zIndex: 99999,
  pointerEvents: "none" as const,
};

export const COMMON_TOOLTIP_PROPS = {
  offset: 8,
  opacity: 1,
};

Then in both components:

+import { COMMON_TOOLTIP_STYLE, COMMON_TOOLTIP_PROPS } from "@/helpers/tooltip.helpers";

 <Tooltip
   id={`delete-${drop.id}`}
   place="top"
-  offset={8}
-  opacity={1}
-  style={{
-    padding: "4px 8px",
-    background: "#37373E",
-    color: "white",
-    fontSize: "13px",
-    fontWeight: 500,
-    borderRadius: "6px",
-    boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
-    zIndex: 99999,
-    pointerEvents: "none",
-  }}>
+  {...COMMON_TOOLTIP_PROPS}
+  style={COMMON_TOOLTIP_STYLE}>
   <span className="tw-text-xs">Delete</span>
 </Tooltip>
components/waves/drops/WaveDropActionsOpen.tsx (1)

37-42: Consider removing redundant SVG sizing attributes.

The SVG element has both width="16" and height="16" attributes (lines 37-38) AND a className="tw-w-4 tw-h-4" (line 42) that sets the same dimensions (tw-w-4 = 1rem = 16px). The Tailwind classes will typically take precedence and are the preferred approach for consistency with the rest of the codebase.

Apply this diff to rely solely on the className:

 <svg
-  width="16"
-  height="16"
   viewBox="0 0 24 24"
   fill="none"
   aria-hidden="true"
   className="tw-w-4 tw-h-4"
   xmlns="http://www.w3.org/2000/svg">
components/waves/leaderboard/header/WaveleaderboardHeader.tsx (1)

70-135: Consider extracting duplicate tooltip styles.

The tooltip style object is identical for both the list view and grid view tooltips (lines 75-85 and 121-131). Extracting this to a constant would reduce duplication and make future updates easier.

const TOOLTIP_STYLE = {
  padding: "4px 8px",
  background: "#37373E",
  color: "white",
  fontSize: "13px",
  fontWeight: 500,
  borderRadius: "6px",
  boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
  zIndex: 99999,
  pointerEvents: "none" as const,
};

Then use it in both tooltips:

 <Tooltip
   id={`list-view-${wave.id}`}
   place="top"
   offset={8}
   opacity={1}
-  style={{
-    padding: "4px 8px",
-    background: "#37373E",
-    color: "white",
-    fontSize: "13px",
-    fontWeight: 500,
-    borderRadius: "6px",
-    boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
-    zIndex: 99999,
-    pointerEvents: "none",
-  }}
+  style={TOOLTIP_STYLE}
 >
components/waves/drops/SubmissionPosition.tsx (2)

26-44: Color class handling looks good; drop the new inline comment to match TSX guidelines

The consolidated colorClasses approach per rank is clear and consistent across all cases. To align with the “no comments in TS/TSX” guideline, you should remove the // Colors for each rank comment and rely on the variable/switch naming instead.

Optionally, you could also move the color strings into a small const map (e.g. const RANK_COLOR_CLASSES: Record<number, string> = { ... }) and use a fallback for the default case to avoid reassigning colorClasses, but that’s purely a readability preference.

-  // Colors for each rank
-  let colorClasses = "";
+  let colorClasses = "";

50-52: Container + icon markup is clean; consider minor accessibility polish

The flex container and spacing classes produce a compact, readable badge, and the shared colorClasses integration is solid. If the trophy icon is purely decorative, consider ensuring it’s hidden from screen readers (e.g. aria-hidden="true" on FontAwesomeIcon) so assistive tech doesn’t announce it redundantly alongside the rank text.

components/waves/drops/ArtistPreviewModalTabs.tsx (1)

1-12: Prefer named React imports and FC alias over React.FC

To match the guideline of preferring direct named imports for React types, consider switching to a named FC import instead of React.FC. This is a non-breaking type-only refactor:

-import React from "react";
+import { FC } from "react";
@@
-export const ArtistPreviewModalTabs: React.FC<ArtistPreviewModalTabsProps> = ({
+export const ArtistPreviewModalTabs: FC<ArtistPreviewModalTabsProps> = ({

This keeps the component fully typed while aligning with the documented style.

components/waves/drops/ArtistWinningArtworksContent.tsx (2)

134-144: Consider using CSS classes instead of inline styles for Tooltip.

The Tooltip component uses inline styles. For consistency with TailwindCSS usage throughout the codebase, consider using the className prop if supported by react-tooltip, or extracting these styles to a shared constant.


86-87: Remove JSX comments per coding guidelines.

The codebase guidelines specify that code should be self-explanatory without comments. The section markers ({/* Content */}, {/* Stats */}, {/* Voters */}, {/* Decision time */}) at lines 86, 98, 114, and 156 could be removed.

components/waves/drops/WaveDropQuote.tsx (1)

28-38: Consider deriving quotedPart directly instead of via useEffect state

quotedPart is fully derivable from drop and partId, but it’s currently managed via useState plus an effect that only depends on drop. This both introduces a potential react-hooks/exhaustive-deps lint warning (missing partId in the deps array) and adds state that isn’t strictly needed.

You can simplify and avoid the lint issue by deriving quotedPart directly:

-import React, { useEffect, useMemo, useState } from "react";
+import React, { useMemo } from "react";
@@
-  const [quotedPart, setQuotedPart] = useState<ApiDropPart | null>(null);
-  useEffect(() => {
-    if (!drop) {
-      return;
-    }
-    const part = drop.parts.find((part) => part.part_id === partId);
-    if (!part) {
-      return;
-    }
-    setQuotedPart(part);
-  }, [drop]);
+  const quotedPart = useMemo(
+    () =>
+      drop?.parts.find((part) => part.part_id === partId) ?? null,
+    [drop, partId],
+  );

This keeps behavior the same, removes unnecessary state/effect, and aligns better with the hook lint rules.

Please confirm this refactor passes your react-hooks ESLint rules and TypeScript checks in the repo’s environment.

components/waves/drop/SingleWaveDropTraits.tsx (1)

478-531: Tighten show‑more button semantics and align with no‑comments guideline

The “Show all / Show less” UX is clear and the state handling is straightforward. A couple of small improvements you might consider:

  • Add type="button" to both <button> elements so they don’t accidentally act as submit buttons if this component ever ends up inside a <form>.
  • Expose state via aria-expanded={showAllTraits} on the toggling button to make the control more accessible.
  • The inline comment at Line 491 (“Always show first 2 items…”) duplicates what the code already expresses and conflicts with the “no comments in TS/TSX” guideline; you can safely drop it. As per coding guidelines, this keeps components self-explanatory without inline comments.

These are non-blocking polish items.

components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)

165-183: Consider extracting tooltip styling to maintain consistency.

The inline styles for the Tooltip could be extracted to a shared constant or CSS module to ensure consistency across similar tooltips in the codebase and reduce duplication.

const VOTER_TOOLTIP_STYLE = {
  padding: "4px 8px",
  background: "#37373E",
  color: "white",
  fontSize: "13px",
  fontWeight: 500,
  borderRadius: "6px",
  boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
  zIndex: 99999,
  pointerEvents: "none" as const,
};

Then use: style={VOTER_TOOLTIP_STYLE}

components/waves/winners/drops/MemesWaveWinnerDrop.tsx (1)

95-119: Simplify redundant conditional logic.

The conditional check for winner.drop.author?.handle renders identical Link components in both branches. The only difference is the tooltip wrapper, but since UserProfileTooltipWrapper automatically handles touch devices internally (returning children without tooltip), you can always use the wrapper.

Apply this diff to simplify the logic:

-                    {winner.drop.author?.handle ? (
-                      <UserProfileTooltipWrapper user={winner.drop.author.handle ?? winner.drop.author.id}>
-                        <Link
-                          href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
-                          onClick={(e) => e.stopPropagation()}
-                          scroll={false}
-                          className="tw-no-underline desktop-hover:hover:tw-underline"
-                        >
-                          <span className="tw-text-sm tw-font-bold tw-text-white">
-                            {winner.drop.author?.handle}
-                          </span>
-                        </Link>
-                      </UserProfileTooltipWrapper>
-                    ) : (
-                      <Link
-                        href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
-                        onClick={(e) => e.stopPropagation()}
-                        scroll={false}
-                        className="tw-no-underline desktop-hover:hover:tw-underline"
-                      >
-                        <span className="tw-text-sm tw-font-bold tw-text-white">
-                          {winner.drop.author?.handle}
-                        </span>
-                      </Link>
-                    )}
+                    <UserProfileTooltipWrapper user={winner.drop.author.handle ?? winner.drop.author.id}>
+                      <Link
+                        href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
+                        onClick={(e) => e.stopPropagation()}
+                        scroll={false}
+                        className="tw-no-underline desktop-hover:hover:tw-underline"
+                      >
+                        <span className="tw-text-sm tw-font-bold tw-text-white">
+                          {winner.drop.author?.handle}
+                        </span>
+                      </Link>
+                    </UserProfileTooltipWrapper>
components/voting/VotingModalButton.tsx (1)

5-15: Variant prop and base classes look good; consider removing inline comment and tightening types

The new variant prop and baseClasses refactor are clean and keep behavior intact. Two small nits:

  • Line 8: the // Add variant prop for styling flexibility comment conflicts with the repo guidelines to avoid code comments in TSX; the code is self-explanatory, so consider removing it.
  • Line 22: you can tighten the event type to React.MouseEvent<HTMLButtonElement> for better TS inference, though current typing is acceptable.

Also applies to: 27-38

components/memes/drops/MemesLeaderboardDropArtistInfo.tsx (1)

38-96: Artist info layout and modal wiring look good; consider fallback for missing handle and trimming comments

The two-row layout (top: handle/CIC/time, bottom: winner badge) and the new ArtistSubmissionBadge click → modal flow are clean and preserve behavior.

Two minor considerations:

  • In the fallback branch where drop.author?.handle is falsy, the link still uses href={\/${drop.author?.handle}`}and renders{drop.author?.handle}. If a truly handle-less author is possible, this will end up as "/undefined"with empty text; consider falling back todrop.author.id` or a generic label in that case.
  • The new JSX comments ({/* Top row: ... */}, /* Bottom row: ... */) go against the “no comments in TSX” guideline; you can safely remove them since the structure and component names already convey intent.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4146890 and a51ab31.

📒 Files selected for processing (45)
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (3 hunks)
  • components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx (1 hunks)
  • components/drops/view/utils/DropVoteProgressing.tsx (2 hunks)
  • components/memes/drops/MemeDropTrait.tsx (2 hunks)
  • components/memes/drops/MemeDropTraits.tsx (3 hunks)
  • components/memes/drops/MemeWinnerDrop.tsx (1 hunks)
  • components/memes/drops/MemesLeaderboardDrop.tsx (4 hunks)
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx (4 hunks)
  • components/memes/drops/MemesLeaderboardDropCard.tsx (1 hunks)
  • components/memes/drops/MemesLeaderboardDropDescription.tsx (1 hunks)
  • components/memes/drops/MemesLeaderboardDropHeader.tsx (1 hunks)
  • components/memes/drops/MemesLeaderboardDropVoteSummary.tsx (1 hunks)
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (3 hunks)
  • components/user/utils/UserCICAndLevel.tsx (1 hunks)
  • components/voting/VotingModalButton.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropAuthor.tsx (2 hunks)
  • components/waves/drop/SingleWaveDropLogs.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropTraits.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVoteContent.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVoteInput.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVoteSubmit.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVoters.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVotes.tsx (3 hunks)
  • components/waves/drops/ArtistActiveSubmissionContent.tsx (1 hunks)
  • components/waves/drops/ArtistPreviewModalTabs.tsx (1 hunks)
  • components/waves/drops/ArtistWinningArtworksContent.tsx (1 hunks)
  • components/waves/drops/SubmissionPosition.tsx (1 hunks)
  • components/waves/drops/WaveDropActionsOpen.tsx (2 hunks)
  • components/waves/drops/WaveDropActionsOptions.tsx (3 hunks)
  • components/waves/drops/WaveDropAuthorPfp.tsx (1 hunks)
  • components/waves/drops/WaveDropQuote.tsx (1 hunks)
  • components/waves/drops/WaveDropRatings.tsx (2 hunks)
  • components/waves/drops/time/WaveDropTime.tsx (1 hunks)
  • components/waves/drops/winner/DefaultWinnerDrop.tsx (2 hunks)
  • components/waves/drops/winner/WinnerDropBadge.tsx (1 hunks)
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx (3 hunks)
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx (1 hunks)
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (1 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (3 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeader.tsx (1 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx (1 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (1 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx (1 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx (1 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • components/waves/drop/SingleWaveDropVoters.tsx
  • components/waves/drops/time/WaveDropTime.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx
  • components/memes/drops/MemesLeaderboardDropHeader.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • components/waves/drop/SingleWaveDropLogs.tsx
  • components/voting/VotingModalButton.tsx
  • components/waves/drops/ArtistPreviewModalTabs.tsx
  • components/memes/drops/MemesLeaderboardDropDescription.tsx
  • components/memes/drops/MemesLeaderboardDropVoteSummary.tsx
  • components/memes/drops/MemeDropTrait.tsx
  • components/drops/view/utils/DropVoteProgressing.tsx
  • components/waves/drops/winner/DefaultWinnerDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteSubmit.tsx
  • components/waves/drops/SubmissionPosition.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/WaveDropQuote.tsx
  • components/waves/drop/SingleWaveDropTraits.tsx
  • components/waves/drops/WaveDropActionsOpen.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/drops/winner/WinnerDropBadge.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeader.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx
  • components/waves/drops/WaveDropAuthorPfp.tsx
  • components/memes/drops/MemesLeaderboardDropCard.tsx
  • components/waves/drops/WaveDropActionsOptions.tsx
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx
  • components/waves/drop/SingleWaveDropAuthor.tsx
  • components/user/utils/UserCICAndLevel.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/MemeDropTraits.tsx
  • components/waves/drops/WaveDropRatings.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

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

Files:

  • components/waves/drop/SingleWaveDropVoters.tsx
  • components/waves/drops/time/WaveDropTime.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx
  • components/memes/drops/MemesLeaderboardDropHeader.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • components/waves/drop/SingleWaveDropLogs.tsx
  • components/voting/VotingModalButton.tsx
  • components/waves/drops/ArtistPreviewModalTabs.tsx
  • components/memes/drops/MemesLeaderboardDropDescription.tsx
  • components/memes/drops/MemesLeaderboardDropVoteSummary.tsx
  • components/memes/drops/MemeDropTrait.tsx
  • components/drops/view/utils/DropVoteProgressing.tsx
  • components/waves/drops/winner/DefaultWinnerDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteSubmit.tsx
  • components/waves/drops/SubmissionPosition.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/WaveDropQuote.tsx
  • components/waves/drop/SingleWaveDropTraits.tsx
  • components/waves/drops/WaveDropActionsOpen.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/drops/winner/WinnerDropBadge.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeader.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx
  • components/waves/drops/WaveDropAuthorPfp.tsx
  • components/memes/drops/MemesLeaderboardDropCard.tsx
  • components/waves/drops/WaveDropActionsOptions.tsx
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx
  • components/waves/drop/SingleWaveDropAuthor.tsx
  • components/user/utils/UserCICAndLevel.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/MemeDropTraits.tsx
  • components/waves/drops/WaveDropRatings.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • components/waves/drop/SingleWaveDropVoters.tsx
  • components/waves/drops/time/WaveDropTime.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx
  • components/memes/drops/MemesLeaderboardDropHeader.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • components/waves/drop/SingleWaveDropLogs.tsx
  • components/voting/VotingModalButton.tsx
  • components/waves/drops/ArtistPreviewModalTabs.tsx
  • components/memes/drops/MemesLeaderboardDropDescription.tsx
  • components/memes/drops/MemesLeaderboardDropVoteSummary.tsx
  • components/memes/drops/MemeDropTrait.tsx
  • components/drops/view/utils/DropVoteProgressing.tsx
  • components/waves/drops/winner/DefaultWinnerDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteSubmit.tsx
  • components/waves/drops/SubmissionPosition.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/WaveDropQuote.tsx
  • components/waves/drop/SingleWaveDropTraits.tsx
  • components/waves/drops/WaveDropActionsOpen.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/drops/winner/WinnerDropBadge.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeader.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx
  • components/waves/drops/WaveDropAuthorPfp.tsx
  • components/memes/drops/MemesLeaderboardDropCard.tsx
  • components/waves/drops/WaveDropActionsOptions.tsx
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx
  • components/waves/drop/SingleWaveDropAuthor.tsx
  • components/user/utils/UserCICAndLevel.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/MemeDropTraits.tsx
  • components/waves/drops/WaveDropRatings.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • components/waves/drop/SingleWaveDropVoters.tsx
  • components/waves/drops/time/WaveDropTime.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx
  • components/memes/drops/MemesLeaderboardDropHeader.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • components/waves/drop/SingleWaveDropLogs.tsx
  • components/voting/VotingModalButton.tsx
  • components/waves/drops/ArtistPreviewModalTabs.tsx
  • components/memes/drops/MemesLeaderboardDropDescription.tsx
  • components/memes/drops/MemesLeaderboardDropVoteSummary.tsx
  • components/memes/drops/MemeDropTrait.tsx
  • components/drops/view/utils/DropVoteProgressing.tsx
  • components/waves/drops/winner/DefaultWinnerDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteSubmit.tsx
  • components/waves/drops/SubmissionPosition.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/WaveDropQuote.tsx
  • components/waves/drop/SingleWaveDropTraits.tsx
  • components/waves/drops/WaveDropActionsOpen.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/drops/winner/WinnerDropBadge.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeader.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx
  • components/waves/drops/WaveDropAuthorPfp.tsx
  • components/memes/drops/MemesLeaderboardDropCard.tsx
  • components/waves/drops/WaveDropActionsOptions.tsx
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx
  • components/waves/drop/SingleWaveDropAuthor.tsx
  • components/user/utils/UserCICAndLevel.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/MemeDropTraits.tsx
  • components/waves/drops/WaveDropRatings.tsx
🧠 Learnings (6)
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • components/waves/drops/time/WaveDropTime.tsx
  • components/drops/view/utils/DropVoteProgressing.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/WaveDropQuote.tsx
  • components/waves/drops/WaveDropActionsOpen.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/drops/winner/WinnerDropBadge.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/leaderboard/header/WaveleaderboardSort.tsx
  • components/waves/leaderboard/header/WaveleaderboardHeader.tsx
  • components/waves/drop/SingleWaveDropAuthor.tsx
  • components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use `<Link href="/path">` for internal navigation instead of plain HTML links

Applied to files:

  • components/waves/drops/WaveDropQuote.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of plain HTML links to satisfy `next/next/no-html-link-for-pages` ESLint rule

Applied to files:

  • components/waves/drops/WaveDropQuote.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 FontAwesome for icons in React components

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: TypeScript + React functional components with hooks; follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Applied to files:

  • components/waves/drop/SingleWaveDropAuthor.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use framework APIs: `<Link>` for internal links, `next/image` for images, adopt Next's ESLint rules

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
🧬 Code graph analysis (13)
components/waves/drops/ArtistActiveSubmissionContent.tsx (2)
components/drops/view/item/content/media/MediaDisplay.tsx (1)
  • MediaDisplay (29-84)
components/waves/drops/SubmissionPosition.tsx (1)
  • SubmissionPosition (10-55)
components/memes/drops/MemesLeaderboardDropVoteSummary.tsx (3)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/drops/view/utils/DropVoteProgressing.tsx (1)
  • DropVoteProgressing (13-79)
__mocks__/react-use.js (1)
  • React (2-2)
components/memes/drops/MemeDropTrait.tsx (2)
hooks/isMobileDevice.ts (1)
  • useIsMobileDevice (5-18)
components/waves/memes/traits/schema.ts (1)
  • FIELD_TO_LABEL_MAP (16-65)
components/drops/view/utils/DropVoteProgressing.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (2)
components/drops/view/utils/DropVoteProgressing.tsx (1)
  • DropVoteProgressing (13-79)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (4)
components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx (1)
  • WaveWinnersDropHeaderAuthorPfp (8-30)
components/user/utils/UserCICAndLevel.tsx (1)
  • UserCICAndLevel (11-53)
helpers/Helpers.ts (2)
  • cicToType (497-515)
  • formatNumberWithCommas (103-120)
components/utils/tooltip/UserProfileTooltipWrapper.tsx (1)
  • UserProfileTooltipWrapper (12-34)
components/waves/drop/SingleWaveDropVotes.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/drops/view/utils/DropVoteProgressing.tsx (1)
  • DropVoteProgressing (13-79)
components/waves/winners/drops/header/WaveWinnersDropHeader.tsx (1)
components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorHandle.tsx (1)
  • WaveWinnersDropHeaderAuthorHandle (10-26)
components/user/utils/UserCICAndLevel.tsx (1)
components/user/utils/raters-table/ProfileRatersTableItem.tsx (1)
  • CIC_COLOR (15-21)
components/waves/drops/ArtistWinningArtworksContent.tsx (2)
components/drops/view/item/content/media/MediaDisplay.tsx (1)
  • MediaDisplay (29-84)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/drops/WaveDropRatings.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
⏰ 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 (44)
components/waves/drop/SingleWaveDropVoteContent.tsx (1)

47-47: Styling updates align with design refresh.

The color palette adjustments (darker iron shades for the MINI layout container and toggle button) are consistent with the PR's styling objectives and maintain visual coherence with the broader component ecosystem. Tailwind utilities are applied correctly, and no functional or accessibility concerns are introduced.

Also applies to: 55-55

components/waves/drops/WaveDropActionsOptions.tsx (2)

26-26: LGTM! Button styling updated appropriately.

The button styling now includes proper hover states, cursor, and transitions for the delete action. The rose hover color appropriately signals a destructive action.


36-36: LGTM! Icon size reduction is consistent.

The SVG icon size reduced from tw-w-5 tw-h-5 to tw-w-4 tw-h-4, consistent with the visual updates across the PR.

components/waves/drops/WaveDropActionsOpen.tsx (1)

32-32: LGTM! Button styling updated appropriately.

The button styling includes proper hover states and transitions for the open action. The white hover color appropriately differentiates this from the destructive delete action.

components/waves/leaderboard/header/WaveleaderboardSort.tsx (2)

102-109: LGTM! Clean styling refresh.

The button styling updates are well-structured and consistent. The use of the getButtonClassName helper function keeps the code maintainable and DRY.


114-114: Approve the container styling update.

The addition of the border and updated padding/background aligns well with the broader UI refresh.

components/waves/leaderboard/header/WaveleaderboardHeader.tsx (1)

43-50: Approve the button styling updates.

The increase in button size (from h-8/w-7 to h-9/w-9) and the updated color tokens for active/inactive states improve the visual hierarchy.

components/waves/drops/ArtistPreviewModalTabs.tsx (1)

23-28: Active tab styling change is safe and consistent

The updated active-state classes for the "Active Submissions" tab keep behavior unchanged while aligning with the iron-800 design token and existing shadow/text styling. No issues from a logic or accessibility standpoint given the unchanged semantics and event handling.

components/waves/drops/ArtistWinningArtworksContent.tsx (1)

56-84: LGTM on the card restructuring.

The aspect-square media container with centered content and hover eye-overlay is a clean implementation. The fallback for drops without media (showing text content) is handled appropriately.

components/waves/drops/ArtistActiveSubmissionContent.tsx (1)

113-145: LGTM on the consistent card layout.

The card structure aligns well with ArtistWinningArtworksContent.tsx, maintaining visual consistency across the leaderboard components. The aspect-square media container, hover eye-overlay, and content section follow the same pattern.

components/waves/drops/WaveDropQuote.tsx (1)

144-149: Transition duration utility fix looks correct

The updated className on the wave name link now uses tw-duration-300, which matches the surrounding transition utilities and should behave as intended. No behavioral or accessibility concerns from this change.

components/user/utils/UserCICAndLevel.tsx (1)

24-36: Visual + sizing updates are consistent and type-safe

The updated size maps and wrapper/badge structure look coherent and keep the type coverage correct for all UserCICAndLevelSize variants. Positioning of the CIC dot relative to the badge and the inline-flex wrapper should behave well across the new sizes, with no apparent TS or layout issues.

Also applies to: 39-50

components/waves/drop/SingleWaveDropAuthor.tsx (1)

14-16: Author row refactor + CIC/level badge wiring look good

The new flex wrapper around UserCICAndLevel and the tooltip-wrapped handle keeps the DOM simple and makes the layout more predictable. Prop wiring (level, cicToType(drop.author.cic), UserCICAndLevelSize.SMALL, and the user key for UserProfileTooltipWrapper) is consistent with the respective component contracts, and there are no obvious typing or runtime issues introduced here.

Also applies to: 31-43

components/waves/drop/SingleWaveDropTraits.tsx (1)

31-37: Card trait item styling change is safe and consistent

The new Tailwind classes give the trait cards a clearer card-like affordance and more compact label/value treatment without altering structure or behavior. No functional or typing concerns here.

components/waves/drop/SingleWaveDropVoteInput.tsx (1)

185-185: LGTM!

The styling update to use tw-bg-iron-950 and tw-rounded-md for the MINI variant aligns with the broader visual refresh in this PR.

components/memes/drops/MemesLeaderboardDropDescription.tsx (1)

12-12: LGTM!

The updated typography with smaller text, lighter color, and relaxed leading appropriately styles this as secondary content beneath the header.

components/waves/drops/WaveDropAuthorPfp.tsx (1)

32-32: LGTM!

The avatar container size increase from 40px to 48px with the corresponding sizes prop update maintains proper image optimization and aligns with the broader avatar sizing updates in this PR.

Also applies to: 39-39

components/waves/drops/time/WaveDropTime.tsx (1)

85-85: LGTM!

Using monospace font for timestamps is a good choice as it ensures consistent character widths for time values, and the compact 10px size appropriately de-emphasizes this metadata.

components/memes/drops/MemeWinnerDrop.tsx (1)

52-53: LGTM!

The shadow update with stronger left-edge emphasis (0.5 opacity) creates consistent visual treatment with DefaultWaveWinnerDrop.tsx for first-place winner styling.

components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (1)

26-39: LGTM!

The getRankShadowClass function now uses rgba values with a consistent pattern: stronger left-edge shadow (0.5 opacity) for visual emphasis with softer secondary edges (0.2 opacity). The rank-based color scheme (gold/silver/bronze/gray) is well-chosen.

components/memes/drops/MemesLeaderboardDropHeader.tsx (1)

11-11: LGTM!

The heading now uses bolder weight with pure white color and tighter leading, creating stronger visual hierarchy consistent with the updated header/footer structure across leaderboard components.

components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)

104-108: LGTM!

Good addition of the rank display in the header row with proper conditional rendering.

components/brain/my-stream/votes/MyStreamWaveMyVoteVotes.tsx (1)

17-17: Typography update aligns with design system.

The font weight change from semibold to bold, addition of monospace font, and tight tracking create a more distinct visual hierarchy for the rating display.

components/drops/view/utils/DropVoteProgressing.tsx (2)

37-40: Enhanced badge styling improves visual clarity.

The addition of borders, monospace font, and fixed arrow color creates a more polished and consistent UI for the progress indicator.


55-55: Conditional typography supports responsive design.

The text size adapts based on the subtle prop while maintaining tight tracking for improved readability.

components/waves/drops/WaveDropRatings.tsx (1)

60-65: Typography updates improve voter count readability.

The nested span structure with bold white count and lighter-weight suffix enhances visual hierarchy.

components/waves/drops/winner/WinnerDropBadge.tsx (2)

60-79: Refactor from inline styles to utility classes improves maintainability.

The shift to Tailwind utility classes for rank-specific colors creates a more consistent and maintainable styling approach.


83-100: Simplified badge structure with utility classes.

The updated structure uses currentColor for the dot and border divider, which dynamically inherits the rank-specific text color, reducing redundancy.

components/waves/drops/winner/DefaultWinnerDrop.tsx (2)

65-69: Explicit alpha value in box shadow improves clarity.

Using ${colors.borderColor}80 makes the opacity explicit, improving code readability.


175-186: Badge rendering relocated for better layout control.

Moving the badge from a prop to a sibling element after the header provides more flexibility in layout and stacking order.

components/memes/drops/MemeDropTrait.tsx (2)

10-31: Optional dropId prop enables unique tooltip identifiers.

Adding dropId allows each trait to have a unique tooltip ID when rendered within different drops, preventing tooltip conflicts.


38-69: Card styling updates align with design system.

The bordered card layout with updated typography and consistent tooltip styling creates a more polished trait display.

components/waves/drop/SingleWaveDropVotes.tsx (3)

35-50: Typography and layout updates improve vote display.

The flex-wrap container and updated typography (bold, monospace, tight tracking) create a more responsive and visually consistent vote display.


58-73: Proper use of Next.js Image component.

The avatar images correctly use the <Image> component with fill prop and explicit sizing, satisfying Next.js best practices.


88-93: Voter count styling creates clear visual hierarchy.

The bold white count with nested muted label for "voter"/"voters" improves readability.

components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (2)

47-52: Nested span structure improves typography control.

Wrapping the voting credit type in nested spans allows for more granular styling control while maintaining semantic structure.


88-93: Voter count styling matches design system.

The bold white count with inline muted suffix creates consistent visual hierarchy across voter displays.

components/waves/winners/drops/header/WaveWinnersDropOutcome.tsx (1)

64-64: LGTM!

Typography update improves visual hierarchy by making the "Outcome:" label more prominent.

components/waves/drop/SingleWaveDropVoteSubmit.tsx (1)

274-274: LGTM!

Removing exclamation marks creates a more subdued, professional tone for the voting button states.

components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (1)

32-38: LGTM!

Styling updates improve visual consistency and prevent text wrapping issues. The increased gap and bolder font weight enhance readability.

components/waves/winners/drops/header/WaveWinnersDropHeader.tsx (1)

23-34: LGTM!

The layout refactor from horizontal to vertical flow improves the header structure and aligns with the broader UI updates across the PR.

components/memes/drops/MemesLeaderboardDropCard.tsx (1)

16-20: LGTM!

Border color updates improve consistency by using Tailwind utility classes and create more subtle hover effects with adjusted opacity values.

components/memes/drops/MemeDropTraits.tsx (1)

41-84: Traits layout and dropId propagation look solid

The updated container layout, dropId wiring into MemeDropTrait, and the refined “Show less/Show all” button styling are coherent and preserve behavior while improving structure and readability. No issues from a logic or typing standpoint.

components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx (1)

41-59: Voter cluster and count typography changes look correct

The refactored inner flex wrapper, tighter avatar spacing, and split number/label styling are all consistent with the surrounding design. Mapping over winner.drop.top_raters and the voter count pluralization remain correct.

Comment thread components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
Comment thread components/memes/drops/MemesLeaderboardDrop.tsx
Comment thread components/waves/drops/ArtistActiveSubmissionContent.tsx Outdated
Comment thread components/waves/drops/ArtistWinningArtworksContent.tsx
Comment thread components/waves/winners/drops/MemesWaveWinnerDrop.tsx Outdated
Comment thread components/waves/winners/drops/MemesWaveWinnerDrop.tsx
Signed-off-by: ragnep <ragneinfo@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
components/memes/drops/MemesLeaderboardDrop.tsx (1)

142-146: Replace <img> with Next.js <Image> component.

This violates the @next/next/no-img-element ESLint rule. As per coding guidelines, use the next/image component for optimized image handling.

+import Image from "next/image";

Then update the voter avatar rendering:

                            {voter.profile.pfp ? (
-                              <img
-                                className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
-                                src={voter.profile.pfp}
-                                alt="Recent voter"
-                              />
+                              <Image
+                                className="tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
+                                src={voter.profile.pfp}
+                                alt={`${voter.profile.handle}'s avatar`}
+                                width={24}
+                                height={24}
+                              />
                            ) : (
🧹 Nitpick comments (7)
__tests__/components/waves/drop/SingleWaveDropTraits.test.tsx (1)

521-523: Use String.raw for the CSS selector to avoid double escaping the backslash

The selector is correct but the 1\\.5 requires double escaping at the JS level. Using String.raw keeps the CSS escape while simplifying the string and addressing the static analysis warning.

-      const metadataItems = container.querySelectorAll(
-        ".tw-px-3.tw-py-1\\.5.tw-rounded-md.tw-bg-iron-900"
-      );
+      const metadataItems = container.querySelectorAll(
+        String.raw`.tw-px-3.tw-py-1\.5.tw-rounded-md.tw-bg-iron-900`
+      );
components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)

147-196: Well-implemented voter display with avatar stack and tooltips.

The new implementation replaces the static voter count with an interactive avatar stack showing top raters with tooltips. The code properly handles edge cases with optional chaining, formats numbers with commas, and includes proper event handling.

Two optional refinements:

  1. Alt text specificity (line 160): Consider using alt={voter.profile.handle} instead of the generic "Recent voter" for better accessibility.

  2. Tooltip styling (lines 173-183): The inline styles with hard-coded values like #37373E could be extracted to a shared constant if these tooltips are used elsewhere, improving maintainability.

components/memes/drops/MemesLeaderboardDrop.tsx (1)

73-74: Consider removing JSX comments.

Per coding guidelines, code should be self-explanatory without comments. The section comments (lines 73, 90, 115, 132) could be removed as the component structure is clear from the element hierarchy.

components/waves/winners/drops/MemesWaveWinnerDrop.tsx (1)

81-82: Consider removing JSX comments for consistency.

Similar to the other file in this PR, section marker comments could be removed per coding guidelines that state code should be self-explanatory.

components/waves/drops/ArtistWinningArtworksContent.tsx (3)

1-26: Prefer named React imports over React.FC

To align with the guidelines, switch from the default React import + React.FC to a named FC type import (and you can drop the default React import):

-import React from "react";
+import type { FC } from "react";
@@
-export const ArtistWinningArtworksContent: React.FC<
-  ArtistWinningArtworksContentProps
-> = ({ user, isOpen, onDropClick }) => {
+export const ArtistWinningArtworksContent: FC<ArtistWinningArtworksContentProps> = ({
+  user,
+  isOpen,
+  onDropClick,
+}) => {

As per coding guidelines, prefer direct named imports for React types.


60-75: Simplify and harden primary media selection logic

The check drop.parts?.[0]?.media && drop.parts[0].media.length > 0 is correct but a bit hard to read and repeats the indexing. Consider computing the primary media once and using optional chaining on length:

-                  <div className="tw-w-full tw-h-full tw-flex tw-items-center tw-justify-center">
-                    {drop.parts?.[0]?.media &&
-                    drop.parts[0].media.length > 0 ? (
-                      <MediaDisplay
-                        media_url={drop.parts[0].media[0].url}
-                        media_mime_type={drop.parts[0].media[0].mime_type}
-                        disableMediaInteraction={true}
-                      />
-                    ) : (
+                  <div className="tw-w-full tw-h-full tw-flex tw-items-center tw-justify-center">
+                    {(() => {
+                      const primaryMedia = drop.parts?.[0]?.media?.[0];
+                      if (!primaryMedia) {
+                        return (
+                          <div className="tw-w-full tw-h-full tw-bg-iron-950 tw-rounded-lg tw-flex tw-items-center tw-justify-center tw-p-4">
+                            <p className="tw-text-iron-300 tw-text-sm tw-line-clamp-6 tw-text-center">
+                              {drop.parts?.[0]?.content || "No content"}
+                            </p>
+                          </div>
+                        );
+                      }
+                      return (
+                        <MediaDisplay
+                          media_url={primaryMedia.url}
+                          media_mime_type={primaryMedia.mime_type}
+                          disableMediaInteraction={true}
+                        />
+                      );
+                    })()}
+                  </div>
-                      <div className="tw-w-full tw-h-full tw-bg-iron-950 tw-rounded-lg tw-flex tw-items-center tw-justify-center tw-p-4">
-                        <p className="tw-text-iron-300 tw-text-sm tw-line-clamp-6 tw-text-center">
-                          {drop.parts?.[0]?.content || "No content"}
-                        </p>
-                      </div>
-                    )}
-                  </div>

This avoids repeated indexing and keeps the null/empty checks in one place.


159-183: Unify icon library usage and remove section comments

You’re mixing FontAwesome (faTrophy) and Heroicons (CalendarDaysIcon) in the same component. Guidelines prefer FontAwesome for icons in React components; consider replacing CalendarDaysIcon with the equivalent FontAwesome calendar icon and dropping the Heroicons import:

-import { CalendarDaysIcon } from "@heroicons/react/24/outline";
+import { faCalendarDays } from "@fortawesome/free-solid-svg-icons";
@@
-                    ) : (
-                      <>
-                        <CalendarDaysIcon className="tw-w-4 tw-h-4 tw-flex-shrink-0" />
+                    ) : (
+                      <>
+                        <FontAwesomeIcon
+                          icon={faCalendarDays}
+                          className="tw-w-4 tw-h-4 tw-flex-shrink-0"
+                        />

Also, the {/* Decision time */} comment can be removed to keep TSX free of comments per the coding guidelines.
As per coding guidelines, prefer FontAwesome icons and comment-free TSX.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a51ab31 and 47621fa.

📒 Files selected for processing (10)
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx (1 hunks)
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx (1 hunks)
  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx (1 hunks)
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (3 hunks)
  • components/memes/drops/MemesLeaderboardDrop.tsx (4 hunks)
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (4 hunks)
  • components/waves/drops/ArtistActiveSubmissionContent.tsx (1 hunks)
  • components/waves/drops/ArtistWinningArtworksContent.tsx (2 hunks)
  • components/waves/drops/time/WaveDropTime.tsx (1 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/waves/drops/time/WaveDropTime.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}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

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

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/@(__tests__|*.test).{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Tests should live in __tests__/ or ComponentName.test.tsx; mock external dependencies and APIs in tests

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

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

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
__tests__/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (tests/AGENTS.md)

__tests__/**/*.{ts,tsx,js}: Prefer for...of loops over forEach as it allows break/continue and works with async/await
Use array.at(-1) and array.at(-2) instead of index-based array access for negative indexing
Use String.prototype.replaceAll() instead of replace() for global string replacements
Use globalThis.fetch() instead of direct fetch() calls
Organize imports with one import per module in order: external → internal → types, with no duplicates
Use element.remove() instead of parent.removeChild(element) for DOM manipulation
Catch errors only when meaningful; no empty catch blocks; log errors with context
Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (?.)

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
__tests__/**/{components,contexts,hooks}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use semantic HTML elements (<label>, <output>) over ARIA attributes when possible; every form control must have a label

Files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Test high-risk areas including happy path workflows, invalid input errors, edge cases/boundaries, component & API interactions, and performance/security when relevant

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/{components,contexts,hooks}/**/*.{ts,tsx} : Use semantic HTML elements (`<label>`, `<output>`) over ARIA attributes when possible; every form control must have a label

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Test accessibility with keyboard navigation and screen reader compatibility

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Write tests following Arrange – Act – Assert pattern with one behaviour per test and clear, descriptive names

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `element.remove()` instead of `parent.removeChild(element)` for DOM manipulation

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx} : Functions must have ≤ 15 cognitive complexity; extract deep ternaries (>3 levels) and break down complex logic

Applied to files:

  • __tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx
  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/@(__tests__|*.test).{ts,tsx} : Tests should live in `__tests__/` or `ComponentName.test.tsx`; mock external dependencies and APIs in tests

Applied to files:

  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • components/waves/drops/ArtistActiveSubmissionContent.tsx
  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/components/**/*.test.{ts,tsx} : Use testing-library/react + user-event for React component tests

Applied to files:

  • __tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx
  • __tests__/components/waves/drop/SingleWaveDropTraits.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} : Do not include any comments in the code; it should be self-explanatory

Applied to files:

  • components/waves/drops/ArtistActiveSubmissionContent.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/__tests__/**/*.test.{ts,tsx,js} : Keep tests independent, deterministic, and fast with production-like data

Applied to files:

  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/*.{ts,tsx,js} : Use `String.prototype.replaceAll()` instead of `replace()` for global string replacements

Applied to files:

  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use framework APIs: `<Link>` for internal links, `next/image` for images, adopt Next's ESLint rules

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Replace `<img>` elements with `<Image />` from `next/image` to satisfy `next/next/no-img-element` ESLint rule

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use framework APIs: internal links should use `<Link>`, images should use `next/image`, and adopt Next's ESLint rules (Core Web Vitals)

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Replace `<img>` elements with `<Image />` from `next/image`

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.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 TailwindCSS for styling in React components

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)

Applied to files:

  • components/memes/drops/MemesLeaderboardDrop.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of plain HTML links to satisfy `next/next/no-html-link-for-pages` ESLint rule

Applied to files:

  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.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 FontAwesome for icons in React components

Applied to files:

  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript and React functional components with hooks

Applied to files:

  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
🧬 Code graph analysis (5)
components/waves/drops/ArtistActiveSubmissionContent.tsx (2)
components/drops/view/item/content/media/MediaDisplay.tsx (1)
  • MediaDisplay (29-84)
components/waves/drops/SubmissionPosition.tsx (1)
  • SubmissionPosition (10-55)
components/memes/drops/MemesLeaderboardDrop.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/drops/ArtistWinningArtworksContent.tsx (2)
components/drops/view/item/content/media/MediaDisplay.tsx (1)
  • MediaDisplay (29-84)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (2)
components/drops/view/utils/DropVoteProgressing.tsx (1)
  • DropVoteProgressing (13-79)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (1)
helpers/Helpers.ts (2)
  • cicToType (497-515)
  • formatNumberWithCommas (103-120)
🪛 GitHub Check: SonarCloud Code Analysis
__tests__/components/waves/drop/SingleWaveDropTraits.test.tsx

[warning] 522-522: String.raw should be used to avoid escaping \.

See more on https://sonarcloud.io/project/issues?id=6529-Collections_6529seize-frontend&issues=AZsIPSbahCqnBr6RMNQZ&open=AZsIPSbahCqnBr6RMNQZ&pullRequest=1639

⏰ 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/brain/my-stream/votes/MyStreamWaveMyVote.tsx (3)

10-10: LGTM: Import additions are all utilized.

The new imports (formatNumberWithCommas, Tooltip, Image) are properly used throughout the voter display implementation.

Also applies to: 14-15


105-105: LGTM: Clean layout improvement.

Moving the rank badge to the header alongside the title creates a better visual hierarchy and reduces vertical space usage.

Also applies to: 109-109


157-163: Image component correctly implemented.

The voter avatar now uses Next.js <Image /> with proper width/height props and consistent border radius (tw-rounded-md), addressing the previous review feedback.

components/memes/drops/MemesLeaderboardDrop.tsx (1)

119-165: LGTM on the footer restructuring.

The responsive layout using container queries, proper event propagation handling, and voter count formatting with pluralization are well implemented.

components/waves/winners/drops/MemesWaveWinnerDrop.tsx (2)

186-228: Good use of Next.js Image component for voter avatars.

The voter display section correctly uses the Image component with explicit dimensions, and the tooltip implementation provides helpful vote details.


79-79: Border styling looks intentional for winner card.

The golden/yellow border with shadow effect (tw-border-[#fbbf24]/20, tw-shadow-[0_0_15px_rgba(251,191,36,0.08)]) provides good visual distinction for winner drops.

__tests__/components/waves/leaderboard/header/WaveleaderboardSort.test.tsx (1)

24-24: Test expectation correctly verifies active button styling.

The component applies tw-bg-white/10 class when the button's sort matches the active sort (line 105 in WaveleaderboardSort.tsx), confirming the test expectation is accurate.

__tests__/components/memes/drops/MemesLeaderboardDropCard.test.tsx (1)

5-17: Test expectations accurately match component implementation.

The parameterized test correctly verifies the border class mappings for all ranks. Each expected class value (tw-border-yellow-500/20, tw-border-iron-400/25, tw-border-amber-600/20, tw-border-iron-700) is confirmed in the component's getBorderClasses function and the test structure properly targets the inner div containing the border classes.

components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (3)

4-4: Image component implementation correctly addresses previous review.

The <img> element has been successfully replaced with the Next.js <Image> component, addressing the previous review comment and satisfying the @next/next/no-img-element ESLint rule. The implementation uses explicit width and height props, which is a valid and simpler approach for fixed-size avatars compared to the fill prop pattern.

As per coding guidelines and previous review feedback.

Also applies to: 64-74


48-50: Typography hierarchy improved for voting credit type.

The text structure has been refined to apply tw-font-medium to the voting credit type label, improving visual hierarchy. This aligns with the PR's objective of UI touch-ups.


55-56: Layout spacing and typography refinements look good.

The spacing adjustments create a cleaner avatar overlap effect (-tw-space-x-2), and the rater count display now uses a bold-to-normal font hierarchy for better visual emphasis. These changes are consistent with the PR's UI touch-up objectives.

Also applies to: 91-96

components/waves/drops/ArtistActiveSubmissionContent.tsx (3)

112-112: LGTM: Refined card styling and interaction timing.

The transition duration reduction to 300ms provides snappier user feedback, and the visual enhancements (borders, shadows, hover states) improve the card presentation quality. The desktop-hover: prefix correctly limits hover effects to appropriate devices.


115-130: LGTM: Improved image presentation and hover affordance.

The aspect-square container ensures consistent grid layout, and the centered MediaDisplay should handle various media types well. The eye icon overlay (lines 123-130) is a nice visual affordance for desktop users indicating the card is clickable. The backdrop blur and opacity transition provide good polish.

Note: The aspect-square enforcement will crop non-square media to fit the 1:1 ratio, which appears intentional for grid consistency.


132-144: LGTM: Cleaner content area structure.

The reorganized layout with border-top separator and flex-based title/badge arrangement improves visual hierarchy and maintainability. The title truncation with tw-min-w-0 and tw-truncate properly handles overflow in constrained spaces.

components/waves/drops/ArtistWinningArtworksContent.tsx (1)

88-113: Stats row refactor looks consistent and clear

The tighter stats row with rating and {drop.wave.voting_credit_type} total is clear, uses formatNumberWithCommas correctly, and keeps typography compact for the card layout. No issues from a logic or type-safety perspective.

Comment thread components/waves/drops/ArtistWinningArtworksContent.tsx
Comment thread components/waves/winners/drops/MemesWaveWinnerDrop.tsx
Signed-off-by: ragnep <ragneinfo@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
components/user/utils/profile/UserProfileTooltip.tsx (1)

18-18: Remove derived-state useEffect/useState for aboutStatement

aboutStatement is fully derived from statements; keeping it in state with an Effect is unnecessary and goes against the guideline to compute derived data during render instead of via Effects. You can simplify and drop both useEffect and useState here while preserving behavior.

A minimal refactor could look like:

-import { useContext, useEffect, useMemo, useState } from "react";
+import { useContext, useMemo } from "react";

-  const [aboutStatement, setAboutStatement] = useState<CicStatement | null>(
-    null
-  );
-
-  useEffect(() => {
-    const about = statements?.find(
-      (statement) =>
-        statement.statement_type === STATEMENT_TYPE.BIO &&
-        statement.statement_group === STATEMENT_GROUP.GENERAL
-    );
-    setAboutStatement(about ?? null);
-  }, [statements]);
+  const aboutStatement = useMemo(
+    () =>
+      statements?.find(
+        (statement) =>
+          statement.statement_type === STATEMENT_TYPE.BIO &&
+          statement.statement_group === STATEMENT_GROUP.GENERAL
+      ) ?? null,
+    [statements]
+  );

This keeps the same semantics, avoids extra state/Effect, and aligns with the “derive during render” rule. As per coding guidelines, Effects that only derive state should be removed.

Also applies to: 69-80

♻️ Duplicate comments (1)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (1)

88-120: Header author handle logic looks good; tighten tooltip user typing for safety.

The handle/id branching now behaves correctly, and the fallback text in the else branch is fixed. To better satisfy tsc --noEmit and avoid possible Object is possibly 'undefined' issues, consider making the user prop to UserProfileTooltipWrapper null‑safe:

-                    {winner.drop.author?.handle ? (
-                      <UserProfileTooltipWrapper user={winner.drop.author.handle ?? winner.drop.author.id}>
+                    {winner.drop.author?.handle ? (
+                      <UserProfileTooltipWrapper
+                        user={winner.drop.author?.handle ?? winner.drop.author?.id ?? ""}
+                      >
                         <Link
                           href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
                           onClick={(e) => e.stopPropagation()}
                           scroll={false}
                           className="tw-no-underline desktop-hover:hover:tw-underline"
                         >
                           <span className="tw-text-sm tw-font-bold tw-text-white">
                             {winner.drop.author?.handle}
                           </span>
                         </Link>
                       </UserProfileTooltipWrapper>
                     ) : (

This keeps the runtime behavior the same while avoiding undefined values and aligns with earlier feedback on this block.

🧹 Nitpick comments (6)
components/memes/drops/MemeWinnerArtistInfo.tsx (2)

51-55: Author link fallback behavior is reasonable, but consider deduping slug logic

Using drop.author?.handle ?? drop.author?.id for both the href and display text gives a sensible fallback when the handle is missing. To avoid duplicating this logic and make future changes safer, you could compute a single authorSlug/authorLabel once and reuse it in both branches.


64-64: WinnerDropBadge placement and decisionTime ?? null

Moving WinnerDropBadge directly under the author/time row fits the new layout. Passing decisionTime ?? null is harmless; if WinnerDropBadge already accepts undefined as “no decision time”, you could pass decisionTime directly and drop the nullish coalescing for slightly simpler props.

components/memes/drops/MemeWinnerDrop.tsx (1)

93-93: Confirm fixed media height is desired across all aspect ratios

Hard-coding tw-h-96 on the media container enforces a uniform card height but may letterbox or crop content for very tall/wide assets, depending on how DropListItemContentMedia handles sizing. If you see awkward cropping on some drops, consider an aspect-ratio-based layout instead of a fixed height.

components/waves/winners/drops/MemesWaveWinnerDrop.tsx (3)

3-4: Prefer named React imports and readonly props wrapper.

To align with the React/TS guidelines (named imports for types/hooks and explicit readonly props), you can drop the default React import, use FC/Fragment, and mark the component props as Readonly:

-import React from "react";
+import { FC, Fragment } from "react";
@@
-interface MemesWaveWinnersDropProps {
+interface MemesWaveWinnersDropProps {
   readonly winner: ApiWaveDecisionWinner;
   readonly wave: ApiWave;
   readonly onDropClick: (drop: ExtendedDrop) => void;
 }
@@
-export const MemesWaveWinnersDrop: React.FC<MemesWaveWinnersDropProps> = ({
+export const MemesWaveWinnersDrop: FC<Readonly<MemesWaveWinnersDropProps>> = ({
   winner,
   wave,
   onDropClick,
 }) => {
@@
-                  {topVoters.map((voter) => (
-                    <React.Fragment key={voter.profile.handle}>
+                  {topVoters.map((voter) => (
+                    <Fragment key={voter.profile.handle}>

This keeps behavior identical but better matches the stated style and typing preferences.

Also applies to: 30-40, 188-190


186-221: Harden top voters map: stable keys and handle/id fallbacks.

key={voter.profile.handle} and tooltip IDs based solely on handle can become "undefined" or collide if a voter lacks a handle or multiple voters share one. It also means the tooltip label won’t show an id fallback.

You can centralize the identifier and reuse it for href, key, and tooltip id:

-              <div className="tw-flex tw-items-center tw-gap-2">
-                <div className="tw-flex tw-items-center -tw-space-x-2">
-                  {topVoters.map((voter) => (
-                    <React.Fragment key={voter.profile.handle}>
-                      <Link
-                        href={`/${voter.profile.handle ?? voter.profile.id}`}
-                        onClick={(e) => e.stopPropagation()}
-                        scroll={false}
-                        className="tw-transition-transform desktop-hover:hover:tw-translate-y-[-2px]"
-                        data-tooltip-id={`voter-${voter.profile.handle}-${voter.rating}`}
-                      >
+              <div className="tw-flex tw-items-center tw-gap-2">
+                <div className="tw-flex tw-items-center -tw-space-x-2">
+                  {topVoters.map((voter) => {
+                    const profileIdentifier = voter.profile.handle ?? voter.profile.id;
+                    const tooltipId = `voter-${profileIdentifier}-${voter.rating}`;
+
+                    return (
+                      <Fragment key={profileIdentifier}>
+                        <Link
+                          href={`/${profileIdentifier}`}
+                          onClick={(e) => e.stopPropagation()}
+                          scroll={false}
+                          className="tw-transition-transform desktop-hover:hover:tw-translate-y-[-2px]"
+                          data-tooltip-id={tooltipId}
+                        >
@@
-                      </Link>
-                      <Tooltip
-                        id={`voter-${voter.profile.handle}-${voter.rating}`}
+                      </Link>
+                      <Tooltip
+                        id={tooltipId}
@@
-                      >
-                        {voter.profile.handle} - {formatNumberWithCommas(voter.rating)}
-                      </Tooltip>
-                    </React.Fragment>
-                  ))}
+                      >
+                        {(voter.profile.handle ?? voter.profile.id) ??
+                          ""}{" "}
+                        - {formatNumberWithCommas(voter.rating)}
+                      </Tooltip>
+                    </Fragment>
+                  );})}

This avoids undefined keys/IDs, improves React reconciliation, and ensures labels always show something meaningful.


81-82: Remove new JSX comments to match “no comments” guideline.

Several new JSX comments were added in this component (header, title/description, footer, “User’s vote”). The project guidelines for *.tsx/*.jsx explicitly call for self‑explanatory code without inline comments.

You can safely drop these without affecting behavior:

-          {/* Header section with border */}
@@
-                  {/* Top row: Handle + Timestamp */}
@@
-                  {/* Bottom row: Winner badge */}
@@
-              {/* Show open icon when not a touch device */}
@@
-          {/* Title and Description */}
@@
-          {/* Footer Section: Traits + Vote Summary */}
@@
-              {/* User's vote */}

The structure and naming are already clear enough to convey intent.

Also applies to: 87-88, 127-128, 137-138, 148-149, 170-171, 230-231

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 47621fa and f0c1005.

📒 Files selected for processing (9)
  • __tests__/components/waves/drop/SingleWaveDropTraits.test.tsx (1 hunks)
  • components/memes/drops/MemeParticipationDrop.tsx (1 hunks)
  • components/memes/drops/MemeWinnerArtistInfo.tsx (3 hunks)
  • components/memes/drops/MemeWinnerDrop.tsx (3 hunks)
  • components/user/utils/UserCICAndLevel.tsx (1 hunks)
  • components/user/utils/profile/UserProfileTooltip.tsx (1 hunks)
  • components/waves/drops/participation/EndedParticipationDrop.tsx (2 hunks)
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (2 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/components/waves/drop/SingleWaveDropTraits.test.tsx
  • components/user/utils/UserCICAndLevel.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • components/memes/drops/MemeParticipationDrop.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/drops/participation/EndedParticipationDrop.tsx
  • components/user/utils/profile/UserProfileTooltip.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/memes/drops/MemeWinnerArtistInfo.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

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

Files:

  • components/memes/drops/MemeParticipationDrop.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/drops/participation/EndedParticipationDrop.tsx
  • components/user/utils/profile/UserProfileTooltip.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/memes/drops/MemeWinnerArtistInfo.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • components/memes/drops/MemeParticipationDrop.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/drops/participation/EndedParticipationDrop.tsx
  • components/user/utils/profile/UserProfileTooltip.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/memes/drops/MemeWinnerArtistInfo.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • components/memes/drops/MemeParticipationDrop.tsx
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/drops/participation/EndedParticipationDrop.tsx
  • components/user/utils/profile/UserProfileTooltip.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/memes/drops/MemeWinnerArtistInfo.tsx
🧠 Learnings (10)
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.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 TailwindCSS for styling in React components

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Replace `<img>` elements with `<Image />` from `next/image` to satisfy `next/next/no-img-element` ESLint rule

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Replace `<img>` elements with `<Image />` from `next/image`

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use framework APIs: internal links should use `<Link>`, images should use `next/image`, and adopt Next's ESLint rules (Core Web Vitals)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use framework APIs: `<Link>` for internal links, `next/image` for images, adopt Next's ESLint rules

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of plain HTML links to satisfy `next/next/no-html-link-for-pages` ESLint rule

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/{components,contexts,hooks}/**/*.{ts,tsx} : Use semantic HTML elements (`<label>`, `<output>`) over ARIA attributes when possible; every form control must have a label

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
🧬 Code graph analysis (3)
components/memes/drops/MemeWinnerDrop.tsx (2)
components/memes/drops/MemeWinnerArtistInfo.tsx (1)
  • MemeWinnerArtistInfo (17-78)
components/drops/view/item/content/media/DropListItemContentMedia.tsx (1)
  • DropListItemContentMedia (26-87)
components/waves/drops/participation/EndedParticipationDrop.tsx (1)
helpers/Helpers.ts (1)
  • getTimeAgoShort (575-601)
components/memes/drops/MemeWinnerArtistInfo.tsx (1)
helpers/Helpers.ts (1)
  • getTimeAgoShort (575-601)
⏰ 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 (9)
components/memes/drops/MemeParticipationDrop.tsx (1)

105-109: Header/description spacing tweak looks correct

The updated sm:tw-ml-[3.75rem] margin cleanly shifts the header/description block without touching behavior or responsiveness (mobile remains unchanged). This aligns with the surrounding Tailwind patterns and should improve visual alignment with the artist info/avatar.

components/waves/drops/participation/EndedParticipationDrop.tsx (1)

111-139: Header stacking and badge layout changes look good

The extra inner column wrapper, smaller timestamp (tw-text-xs), and Participant badge container with tw-w-fit keep structure clear, avoid negative margins, and don’t affect any interaction logic. Layout remains predictable for varying handles and should be fine across breakpoints given the existing flex/whitespace utilities.

components/user/utils/profile/UserProfileTooltip.tsx (1)

114-118: Size change to UserCICAndLevelSize.SMALL looks correct

The smaller size is consistent with this compact tooltip layout and the updated sizing in UserCICAndLevel; no functional concerns here.

components/memes/drops/MemeWinnerArtistInfo.tsx (2)

26-38: Header layout/typography changes look consistent

Switching the outer and inner containers to tw-items-start with gaps and tightening the header text styling (tw-text-md, tw-leading-none, tw-font-semibold) is coherent with the rest of the leaderboard card touch‑ups; no behavioral concerns here.


59-62: Time separator and text adjustments are fine

Making the separator always visible and shrinking the time label to tw-text-xs keeps the meta row compact without affecting logic; getTimeAgoShort(drop.created_at) usage remains unchanged and looks correct.

components/memes/drops/MemeWinnerDrop.tsx (4)

1-1: Client component usage is appropriate here

Given the interactive reply/quote handlers and DropMobileMenuHandler/WaveDropActions, keeping this as a client component is appropriate; no changes needed at this line.


5-8: New Drop imports align with usage

Importing DropInteractionParams and DropLocation from the Drop module matches how onReply/onQuote are typed and how location is used from useDropContext. This keeps types and enums centralized and is consistent with the rest of the drops stack.


56-56: Shadow class change is purely visual

Updating firstPlaceShadow to use a stronger primary inset (rgba(251,191,36,0.5)) is a safe, presentational-only tweak and doesn’t affect behavior.


59-59: Outer container margin tweak looks safe

Adding tw-mb-3 to the top-level container is a straightforward spacing adjustment and should integrate cleanly with the leaderboard card list layout.

Comment thread components/memes/drops/MemeWinnerDrop.tsx Outdated
Comment thread components/memes/drops/MemeWinnerDrop.tsx Outdated
Comment thread components/memes/drops/MemeWinnerDrop.tsx Outdated
Signed-off-by: ragnep <ragneinfo@gmail.com>
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (2)

95-119: Consolidate the conditional UserProfileTooltipWrapper logic.

The conditional branching is unnecessary since UserProfileTooltipWrapper already handles touch devices internally by rendering children without the tooltip. The else branch duplicates the Link rendering.

Apply this diff to simplify:

-                    {winner.drop.author?.handle ? (
-                      <UserProfileTooltipWrapper user={winner.drop.author.handle ?? winner.drop.author.id}>
-                        <Link
-                          href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
-                          onClick={(e) => e.stopPropagation()}
-                          scroll={false}
-                          className="tw-no-underline desktop-hover:hover:tw-underline"
-                        >
-                          <span className="tw-text-sm tw-font-bold tw-text-white">
-                            {winner.drop.author?.handle}
-                          </span>
-                        </Link>
-                      </UserProfileTooltipWrapper>
-                    ) : (
-                      <Link
-                        href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
-                        onClick={(e) => e.stopPropagation()}
-                        scroll={false}
-                        className="tw-no-underline desktop-hover:hover:tw-underline"
-                      >
-                        <span className="tw-text-sm tw-font-bold tw-text-white">
-                          {winner.drop.author?.handle ?? winner.drop.author?.id}
-                        </span>
-                      </Link>
-                    )}
+                    <UserProfileTooltipWrapper user={winner.drop.author?.handle ?? winner.drop.author?.id ?? ""}>
+                      <Link
+                        href={`/${winner.drop.author?.handle ?? winner.drop.author?.id}`}
+                        onClick={(e) => e.stopPropagation()}
+                        scroll={false}
+                        className="tw-no-underline desktop-hover:hover:tw-underline"
+                      >
+                        <span className="tw-text-sm tw-font-bold tw-text-white">
+                          {winner.drop.author?.handle ?? winner.drop.author?.id}
+                        </span>
+                      </Link>
+                    </UserProfileTooltipWrapper>

196-201: Replace <img> with Next.js <Image> component.

Using <img> elements violates the @next/next/no-img-element ESLint rule.

As per coding guidelines, replace with Next.js <Image> component:

+import Image from "next/image";

Then update the image rendering:

                        {voter.profile.pfp ? (
-                          <img
-                            className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
-                            src={voter.profile.pfp}
-                            alt="Recent voter"
-                          />
+                          <Image
+                            src={voter.profile.pfp}
+                            alt="Recent voter"
+                            width={24}
+                            height={24}
+                            className="tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
+                          />
                        ) : (
components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)

156-163: Replace <img> with <Image /> from next/image.

The voter avatar rendering uses a raw <img> element, violating the @next/next/no-img-element ESLint rule and project coding guidelines. This issue was previously flagged but the lines were outside the reviewable diff scope.

First, add the Image import at the top of the file:

 import Link from "next/link";
+import Image from "next/image";
 import UserProfileTooltipWrapper from "@/components/utils/tooltip/UserProfileTooltipWrapper";

Then replace the <img> element with <Image />:

                       {voter.profile.pfp ? (
-                          <img
-                            className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
-                            src={voter.profile.pfp}
-                            alt="Recent voter"
-                          />
+                          <Image
+                            src={voter.profile.pfp}
+                            alt="Recent voter"
+                            width={24}
+                            height={24}
+                            className="tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800 tw-object-contain"
+                          />
                         ) : (
                           <div className="tw-w-6 tw-h-6 tw-rounded-md tw-border-2 tw-border-solid tw-border-[#111] tw-bg-iron-800" />
                         )}

As per coding guidelines and learnings.

🧹 Nitpick comments (1)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (1)

40-40: Remove code comments per coding guidelines.

The coding guidelines specify that code should be self-explanatory without comments. The descriptive comments throughout this file can be removed as the code structure and naming are already clear.

As per coding guidelines.

Also applies to: 43-43, 63-63, 70-70, 80-80, 86-86, 126-126, 136-136, 147-147, 169-169, 227-227, 253-253

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0c1005 and 1cc30c0.

📒 Files selected for processing (5)
  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (3 hunks)
  • components/memes/drops/MemeWinnerDrop.tsx (3 hunks)
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx (3 hunks)
  • components/waves/drops/ArtistWinningArtworksContent.tsx (1 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/memes/drops/MemeWinnerDrop.tsx
  • components/waves/drops/ArtistWinningArtworksContent.tsx
  • components/memes/drops/meme-participation-drop/MemeDropVoteStats.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{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}: Replace <img> elements with <Image /> from next/image to satisfy @next/next/no-img-element ESLint rule
Use <Link href="/path"> from Next.js for internal navigation instead of plain HTML links to satisfy @next/next/no-html-link-for-pages ESLint rule

Files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursorrules)

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

Files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)
Use framework APIs: internal links should use <Link>, images should use next/image, and adopt Next's ESLint rules (Core Web Vitals)

**/*.{js,jsx,ts,tsx}: Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)
Follow existing code style and naming conventions; maintain clean code standards (measured by SonarQube)

Files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Must pass tsc --noEmit type checking
Prefer direct named imports for React hooks and types (import { useMemo, useRef, FC, etc. } from "react") over React. namespace usage (React.useMemo, React.useRef, etc.)
If the react-hooks/exhaustive-deps lint rule is triggered: if the Effect only derives state, remove the Effect and compute during render; if listening to an external system and needing fresh props/state, wrap non-reactive logic in useEffectEvent

**/*.{ts,tsx}: Must pass tsc --noEmit for TypeScript type checking
Prefer Server Components over Client Components; use Server Functions/Server Actions ('use server') for mutations
Remove unnecessary Effects; if Effect only derives state, compute during render instead
Use useEffectEvent for non-reactive logic inside Effects to avoid unnecessary re-runs
Use framework APIs: <Link> for internal links, next/image for images, adopt Next's ESLint rules
Use 'use cache' directive and Cache Components features for explicit opt-in caching in Next.js 16
Use TypeScript and React functional components with hooks
When parsing Seize URLs or similar, fail fast if base origin is unavailable; do not fall back to placeholder origins
Replace <img> elements with <Image /> from next/image
Use <Link href="/path"> for internal navigation instead of plain HTML links
Move data fetches to Server Components; handle mutations through Server Functions/Server Actions with 'use server' directive

Files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Replace `<img>` elements with `<Image />` from `next/image`

Applied to files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Replace `<img>` elements with `<Image />` from `next/image` to satisfy `next/next/no-img-element` ESLint rule

Applied to files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Fix with modernization (no `// eslint-disable` unless explicitly instructed); prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions

Applied to files:

  • components/brain/my-stream/votes/MyStreamWaveMyVote.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.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 TailwindCSS for styling in React components

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use framework APIs: internal links should use `<Link>`, images should use `next/image`, and adopt Next's ESLint rules (Core Web Vitals)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{ts,tsx} : Use framework APIs: `<Link>` for internal links, `next/image` for images, adopt Next's ESLint rules

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:30.871Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-05T10:55:30.871Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Code must satisfy ESLint (Next's Core Web Vitals + React Hooks rules)

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-03T14:52:34.271Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-03T14:52:34.271Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use `<Link href="/path">` from Next.js for internal navigation instead of plain HTML links to satisfy `next/next/no-html-link-for-pages` ESLint rule

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
📚 Learning: 2025-12-05T10:55:43.476Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-05T10:55:43.476Z
Learning: Applies to __tests__/**/{components,contexts,hooks}/**/*.{ts,tsx} : Use semantic HTML elements (`<label>`, `<output>`) over ARIA attributes when possible; every form control must have a label

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.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 FontAwesome for icons in React components

Applied to files:

  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
🧬 Code graph analysis (2)
components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (1)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (5)
components/waves/winners/drops/header/WaveWinnersDropHeaderAuthorPfp.tsx (1)
  • WaveWinnersDropHeaderAuthorPfp (8-30)
components/user/utils/UserCICAndLevel.tsx (1)
  • UserCICAndLevel (11-53)
helpers/Helpers.ts (2)
  • cicToType (497-515)
  • formatNumberWithCommas (103-120)
components/utils/tooltip/UserProfileTooltipWrapper.tsx (1)
  • UserProfileTooltipWrapper (12-34)
__mocks__/react-use.js (1)
  • React (2-2)
🔇 Additional comments (5)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (2)

29-33: LGTM!

Props interface correctly uses readonly modifiers and includes all necessary properties.


188-188: Prefer fragment shorthand syntax.

Use the shorthand <> syntax instead of React.Fragment for cleaner code.

Apply this diff:

-                    <React.Fragment key={voter.profile.handle}>
+                    <React.Fragment key={voter.profile.handle}>

Note: Keep React.Fragment in this case since a key prop is required. The shorthand <> doesn't support props.

components/brain/my-stream/votes/MyStreamWaveMyVote.tsx (3)

10-10: LGTM: Import additions support the new voter display feature.

The new imports are correctly used: formatNumberWithCommas formats the vote counts, and Tooltip provides hover information for voter avatars.

Also applies to: 14-14


104-109: LGTM: Rank badge positioning improves layout hierarchy.

Moving the rank badge to align with the title creates a cleaner, more compact header layout. The conditional rendering ensures no empty space when rank is absent.


165-193: LGTM: Tooltip configuration and vote count formatting.

The Tooltip implementation correctly displays voter information with appropriate styling, and the vote counts are properly formatted using formatNumberWithCommas with correct singular/plural handling.

@ragnep ragnep merged commit 892c581 into main Dec 10, 2025
9 checks passed
@ragnep ragnep deleted the leaderboard-card-list-view branch December 10, 2025 15:01
This was referenced Dec 11, 2025
This was referenced Jan 2, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants