Skip to content

Xtdh voting#1648

Merged
simo6529 merged 11 commits intomainfrom
xtdh-voting
Dec 16, 2025
Merged

Xtdh voting#1648
simo6529 merged 11 commits intomainfrom
xtdh-voting

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Dec 15, 2025

Summary by CodeRabbit

  • New Features

    • Two new voting credit types added (XTDH, TDH + XTDH); voting options now follow a standardized order and default to TDH + XTDH.
  • Bug Fixes

    • Stricter validation for voting configurations by credit type.
  • Changes

    • Unified/clarified voting labels across the UI; improved voting input UX (press‑and‑hold, snapping to key values, quick‑percentage controls); avatars and icons updated for clearer display; tooltips and headers reflect new labels.

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

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

coderabbitai Bot commented Dec 15, 2025

Walkthrough

Added two new credit-type enum values and consolidated human-readable voting labels; replaced raw credit-type strings with label lookups across many wave components. Refactored voting inputs/slider/stats to use a label prop and implemented press‑and‑hold memetic snapping. Adjusted create‑wave defaults, ordering, and validation; VoteBreakdownTooltip now shows avatars and accepts ratingsData.

Changes

Cohort / File(s) Summary
API & Constants
openapi.yaml, helpers/waves/waves.constants.ts
Extended ApiWaveCreditType with XTDH / TDH_PLUS_XTDH. Added WAVE_VOTE_STATS_LABELS and updated WAVE_VOTING_LABELS mappings (new keys and adjusted strings); removed an unused export.
Create-wave config & validation
components/waves/create-wave/voting/CreateWaveVoting.tsx, helpers/waves/create-wave.validation.ts, helpers/waves/create-wave.helpers.ts, components/waves/create-wave/hooks/useWaveConfig.ts
Introduced VOTING_TYPES_ORDER to control option ordering and prefixed radio labels with "By ". Changed default voting type to TdhPlusXtdh. Reworked validation to enforce REP vs non‑REP requirements for category/profileId.
Vote input / interaction
components/waves/drop/SingleWaveDropVoteInput.tsx
Replaced creditType prop with label: string; added memetic snapping, quick‑percentage buttons, press‑and‑hold interval/timeout logic, clamping/delta utilities, computeNextVoteValue flow, FontAwesome arrows, and proper timer teardown; MINI/NORMAL render paths updated.
Vote slider / stats / content
components/waves/drop/SingleWaveDropVoteSlider.tsx, components/waves/drop/SingleWaveDropVoteStats.tsx, components/waves/drop/SingleWaveDropVoteContent.tsx
Prop APIs changed from creditType: ApiWaveCreditTypelabel: string. Removed preset-mark logic from slider. Text rendering now uses label and WAVE_VOTE_STATS_LABELS.
Drop vote views & voter UI
components/waves/drop/SingleWaveDropVoter.tsx, components/waves/drop/SingleWaveDropLog.tsx, components/waves/drop/SingleWaveDropVotes.tsx, components/waves/drop/SingleWaveDropVoteContent.tsx
Replaced raw credit‑type displays with WAVE_VOTING_LABELS[...] and WAVE_VOTE_STATS_LABELS; migrated some <img> → Next.js Image; updated arrow/icon usage.
Participation ratings & tooltip
components/waves/drops/participation/ratings/*.tsx, components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
Replaced hardcoded "Your votes"/"Total" and credit‑type strings with WAVE_VOTE_STATS_LABELS and WAVE_VOTING_LABELS. VoteBreakdownTooltip now derives voting label, shows an avatar (pfp) from auth/identity/context, and its props include ratingsData.
Leaderboards, winners & podium
components/waves/leaderboard/**/*, components/waves/winners/**/*, components/waves/winners/podium/WavePodiumItem.tsx
Replaced raw voting_credit_type text with mapped WAVE_VOTING_LABELS[...] and WAVE_VOTE_STATS_LABELS across leaderboard and winner components. Podium: Next/Image for avatars, added decorative badge, layout/tooltip wrapper and author/rating adjustments.
Specs & misc UI tweaks
components/waves/specs/*.tsx, components/drops/view/DropsList.tsx, components/waves/drops/wave-drops-all/index.tsx
Added/updated credit‑type label mappings in specs, renamed "Rating" → "Voting" in WaveSpecs, removed unused imports/constants, adjusted memo deps and minor formatting changes.
Tests & group create
__tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx, __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts , components/groups/page/create/GroupCreate.tsx, components/groups/page/create/config/GroupCreateTDH.tsx
Tests updated to reflect TdhPlusXtdh / inclusion strategy changes; group-create default inclusion_strategy changed to Both and UI options adjusted.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas needing extra attention:

  • components/waves/drop/SingleWaveDropVoteInput.tsx — press‑and‑hold timing, interval/timeout lifecycle, snapping logic, accessibility and MINI vs NORMAL parity.
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx — new hooks (useAuth/useIdentity/useSeizeConnectContext), avatar selection, and added ratingsData prop.
  • helpers/waves/create-wave.validation.ts — REP vs non‑REP validation changes that affect allowed configs.
  • components/waves/winners/podium/WavePodiumItem.tsx — layout and click/propagation behavior after Next/Image and DOM rearrangement.

Possibly related PRs

Suggested reviewers

  • ragnep
  • prxt6529

Poem

"I hopped through enums and nudged each name,
Labels now tidier, no two sound the same.
I hold and watch the numbers softly glide,
Avatars smile where voting labels bide.
A rabbit cheers — the waves are set to ride 🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The pull request title 'Xtdh voting' is vague and generic, using a technical term without clearly conveying what changes or improvements were made to the codebase. Expand the title to clearly describe the main change, such as 'Add XTDH and TDH+XTDH voting credit types' or 'Support XTDH voting alongside existing credit types'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 xtdh-voting

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

🧹 Nitpick comments (2)
helpers/waves/waves.constants.ts (1)

15-25: Voting labels and stats labels look correct and aligned with ApiWaveCreditType.

All credit types (including XTDH and TDH_PLUS_XTDH) are covered, and labels are consistent. If you want slightly stronger typing for the stats keys, you can add as const:

export const WAVE_VOTE_STATS_LABELS = {
  YOUR_VOTES: "Your votes",
  TOTAL: "Total",
} as const;
components/waves/drop/SingleWaveDropVoteInput.tsx (1)

148-177: Minor UX and style notes: quick percentages and labels are solid, but remove JSX comments and rely on labels from constants.

  • getQuickPercentageButtonClass and the quick-percentage arrays look fine and correctly derive selection/negative state.
  • Both MINI and NORMAL inputs now consistently display {WAVE_VOTING_LABELS[creditType]}, which keeps voting units in sync across the UI.

Two small cleanups to align with repo guidelines:

  1. Remove JSX comments in TSX

    • Lines like {/* Input and buttons on one row */} and the comments around quick-percentage sections violate the “no comments in code” rule.
    • You can safely delete these without impacting readability, since the JSX structure is self-explanatory.
  2. Simplify type usage for voteValue

    • Since voteValue is already number | string, you can keep using Number(voteValue) in getQuickPercentageButtonClass and rely on clamping logic you already have; that part is fine as-is.

Example for comment removal:

-      <div className="tw-flex tw-flex-col">
-        {/* Input and buttons on one row */}
+      <div className="tw-flex tw-flex-col">
@@
-        {/* Quick percentage buttons below */}
         <div className="tw-mt-1.5 tw-flex tw-gap-1 tw-overflow-x-auto tw-scrollbar-thin tw-scrollbar-thumb-iron-500 tw-scrollbar-track-iron-800 hover:tw-scrollbar-thumb-iron-300">
-          {/* Mobile percentages */}
           <div className="sm:tw-hidden tw-flex tw-gap-1">
@@
-          {/* Full percentages for sm and above */}
           <div className="tw-hidden sm:tw-flex tw-gap-1">

Also applies to: 199-305

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e207bb0 and 558d20f.

⛔ Files ignored due to path filters (1)
  • generated/models/ApiWaveCreditType.ts is excluded by !**/generated/**
📒 Files selected for processing (19)
  • components/waves/create-wave/voting/CreateWaveVoting.tsx (2 hunks)
  • components/waves/drop/SingleWaveDropLog.tsx (5 hunks)
  • components/waves/drop/SingleWaveDropVoteContent.tsx (3 hunks)
  • components/waves/drop/SingleWaveDropVoteInput.tsx (2 hunks)
  • components/waves/drop/SingleWaveDropVoteSlider.tsx (4 hunks)
  • components/waves/drop/SingleWaveDropVoteStats.tsx (2 hunks)
  • components/waves/drop/SingleWaveDropVoter.tsx (3 hunks)
  • components/waves/drop/SingleWaveDropVotes.tsx (5 hunks)
  • components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx (2 hunks)
  • components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx (4 hunks)
  • components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx (2 hunks)
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (4 hunks)
  • components/waves/specs/WaveNotificationSettings.tsx (0 hunks)
  • components/waves/specs/WaveRating.tsx (1 hunks)
  • components/waves/specs/WaveRatingRep.tsx (0 hunks)
  • components/waves/specs/WaveSpecs.tsx (1 hunks)
  • helpers/waves/create-wave.validation.ts (2 hunks)
  • helpers/waves/waves.constants.ts (1 hunks)
  • openapi.yaml (1 hunks)
💤 Files with no reviewable changes (2)
  • components/waves/specs/WaveNotificationSettings.tsx
  • components/waves/specs/WaveRatingRep.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/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx
  • helpers/waves/create-wave.validation.ts
  • components/waves/specs/WaveRating.tsx
  • components/waves/specs/WaveSpecs.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx
  • helpers/waves/waves.constants.ts
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
  • components/waves/create-wave/voting/CreateWaveVoting.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drop/SingleWaveDropLog.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/SingleWaveDropVotes.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx
  • components/waves/specs/WaveRating.tsx
  • components/waves/specs/WaveSpecs.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
  • components/waves/create-wave/voting/CreateWaveVoting.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drop/SingleWaveDropLog.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/SingleWaveDropVotes.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx
  • helpers/waves/create-wave.validation.ts
  • components/waves/specs/WaveRating.tsx
  • components/waves/specs/WaveSpecs.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx
  • helpers/waves/waves.constants.ts
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
  • components/waves/create-wave/voting/CreateWaveVoting.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drop/SingleWaveDropLog.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/SingleWaveDropVotes.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx
  • helpers/waves/create-wave.validation.ts
  • components/waves/specs/WaveRating.tsx
  • components/waves/specs/WaveSpecs.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx
  • helpers/waves/waves.constants.ts
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
  • components/waves/create-wave/voting/CreateWaveVoting.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteStats.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drop/SingleWaveDropLog.tsx
🧠 Learnings (10)
📚 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} : Prefer Server Components over Client Components; use Server Functions/Server Actions (`'use server'`) for mutations

Applied to files:

  • components/waves/drop/SingleWaveDropVotes.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: Move data fetching from client-side Effects to Server Components for reads; use Server Functions / Server Actions (`'use server'`) for mutations

Applied to files:

  • components/waves/drop/SingleWaveDropVotes.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: Prefer Server Components over Client Components where possible; data reads should use Server Components with inline fetches; mutations should use Server Functions / Server Actions (`'use server'`); avoid client Effects for data fetching unless truly needed

Applied to files:

  • components/waves/drop/SingleWaveDropVotes.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/specs/WaveRating.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/waves/specs/WaveRating.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/specs/WaveSpecs.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/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/drop/SingleWaveDropVoteInput.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/drop/SingleWaveDropLog.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/drop/SingleWaveDropLog.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/drop/SingleWaveDropLog.tsx
🧬 Code graph analysis (9)
components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx (1)
helpers/waves/waves.constants.ts (2)
  • WAVE_VOTE_STATS_LABELS (15-18)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (5)
components/auth/SeizeConnectContext.tsx (1)
  • useSeizeConnectContext (618-626)
components/auth/Auth.tsx (1)
  • useAuth (95-97)
hooks/useIdentity.ts (1)
  • useIdentity (18-34)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx (1)
helpers/waves/waves.constants.ts (2)
  • WAVE_VOTE_STATS_LABELS (15-18)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteSlider.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/create-wave/voting/CreateWaveVoting.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoter.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteInput.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropLog.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
⏰ 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 (14)
components/waves/drop/SingleWaveDropLog.tsx (1)

9-9: LGTM! Label centralization improves consistency.

The refactor to use WAVE_VOTING_LABELS[creditType] ensures consistent display of voting credit types across the UI.

Also applies to: 115-115, 142-142

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

7-7: LGTM! Consistent label usage.

Aligns with the centralized labeling approach used throughout the PR.

Also applies to: 93-93

components/waves/drop/SingleWaveDropVoteSlider.tsx (2)

26-30: LGTM! Interface correctly reflects implementation.

The position field is used in calculatePresetMarks function (lines 107, 120, 131, 141), so adding it to the interface properly types the existing usage.


10-10: LGTM! Consistent label usage.

Aligns with the centralized labeling approach used throughout the PR.

Also applies to: 302-302

components/waves/specs/WaveRating.tsx (1)

7-8: LGTM! Credit type mappings extended correctly.

The new mappings for Xtdh and TdhPlusXtdh align with the extended ApiWaveCreditType enum and match the labels used in WAVE_VOTING_LABELS constant.

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

3-6: LGTM! Comprehensive label centralization.

Replacing hardcoded strings with WAVE_VOTE_STATS_LABELS and WAVE_VOTING_LABELS improves maintainability and prepares the codebase for potential internationalization.

Also applies to: 23-25, 30-30, 37-37

helpers/waves/create-wave.validation.ts (1)

178-199: LGTM! Validation correctly extends to all non-Rep credit types.

The updated logic voting.type !== ApiWaveCreditType.Rep properly restricts category and profileId for all non-Rep credit types (TDH, XTDH, TDH+XTDH), which is correct since only Rep voting should have these attributes.

Note: The error constants still reference "TDH_VOTING" (lines 181, 184) but now apply to all non-Rep types. While the logic is correct, consider updating the error constant names in a future refactor for clarity.

components/waves/create-wave/voting/CreateWaveVoting.tsx (2)

14-19: LGTM! Explicit ordering ensures deterministic rendering.

The VOTING_TYPES_ORDER constant replaces the non-deterministic Object.values(ApiWaveCreditType) iteration, ensuring voting type options always render in the intended order: TDH, XTDH, TDH + XTDH, Rep.

Also applies to: 65-67


73-73: Note: Label prefix added, not removed.

The label now includes the "By " prefix (e.g., "By TDH", "By Rep"). Note that this contradicts the AI summary which mentions "removing 'By' prefixes" - the code actually adds them.

components/waves/drops/participation/ratings/ParticipationDropRatingsVoterSection.tsx (1)

10-15: Centralizing tooltip unit labels via WAVE_VOTING_LABELS is correct.

Using WAVE_VOTING_LABELS[drop.wave.voting_credit_type] in the tooltip keeps the displayed unit consistent with the rest of the waves UI and automatically supports the new XTDH and TDH_PLUS_XTDH values.

Also applies to: 56-59

openapi.yaml (1)

6994-7002: Extending ApiWaveCreditType with XTDH and TDH_PLUS_XTDH is consistent and safe.

The new enum values integrate cleanly with existing references (e.g., ApiWaveMin.voting_credit_type and ApiWaveVotingConfig.credit_type) and match the frontend label mappings, so generated clients will be able to use them without additional schema changes.

components/waves/specs/WaveSpecs.tsx (1)

37-37: LGTM!

The label update from "Rating" to "Voting" aligns with the PR's objective to refactor voting-related terminology across wave components.

components/waves/drops/participation/ratings/ParticipationDropRatingsUserSection.tsx (1)

3-6: LGTM!

The refactoring consolidates hardcoded UI strings into shared constants (WAVE_VOTE_STATS_LABELS and WAVE_VOTING_LABELS), improving maintainability and consistency across the codebase.

Also applies to: 30-30, 40-40

components/waves/drops/participation/ratings/ParticipationDropRatingsTotalSection.tsx (1)

6-9: LGTM. The refactoring correctly uses WAVE_VOTE_STATS_LABELS and WAVE_VOTING_LABELS with the proper ApiWaveCreditType definitions.

Comment thread components/waves/drop/SingleWaveDropVoteContent.tsx Outdated
Comment thread components/waves/drop/SingleWaveDropVoteInput.tsx Outdated
Comment thread components/waves/drop/SingleWaveDropVotes.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (11)
components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx (2)

61-61: Consider extracting the repeated label expression to a variable.

The expression WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] is used three times (lines 61, 102, 118). Extracting it to a constant improves readability and ensures consistency.

 export const WaveLeaderboardDropRaters: React.FC<
   WaveLeaderboardDropRatersProps
 > = ({ drop }) => {
   const votersCountLabel = drop.raters_count === 1 ? "voter" : "voters";
   const userVote = drop.context_profile_context?.rating ?? 0;
   const isNegativeVote = userVote < 0;
+  const votingLabel = WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType];

Then use votingLabel at lines 61, 102, and 118.


76-83: Consider using next/image for the avatar.

The <img> element should be replaced with <Image /> from next/image per coding guidelines. While this isn't part of the current changes, it's worth addressing.

+import Image from "next/image";
-                    <img
-                      src={getScaledImageUri(
-                        voter.profile.pfp,
-                        ImageScale.W_AUTO_H_50
-                      )}
-                      alt={`${voter.profile.handle}'s Profile`}
-                      className="tw-h-5 tw-w-5 tw-rounded-md tw-ring-1 tw-ring-black tw-bg-iron-800 tw-object-contain"
-                    />
+                    <Image
+                      src={getScaledImageUri(
+                        voter.profile.pfp,
+                        ImageScale.W_AUTO_H_50
+                      )}
+                      alt={`${voter.profile.handle}'s Profile`}
+                      width={20}
+                      height={20}
+                      className="tw-h-5 tw-w-5 tw-rounded-md tw-ring-1 tw-ring-black tw-bg-iron-800 tw-object-contain"
+                    />
components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx (1)

188-191: Consider adding a safe fallback for unmapped credit types

Using WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] makes the UI friendlier, assuming the map is exhaustive for all ApiWaveCreditType values. If there is any chance of a new/unknown voting_credit_type coming from the API, this could render undefined in the UI.

You might want to precompute the label with a fallback to the raw value (or a generic label), e.g. in the render body:

const votingCreditType = drop.wave.voting_credit_type as ApiWaveCreditType;
const votingCreditLabel = WAVE_VOTING_LABELS[votingCreditType] ?? votingCreditType;

and then use votingCreditLabel in JSX.

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

4-5: Consistent use of WAVE_VOTING_LABELS for credit type display

Using WAVE_VOTING_LABELS[winner.drop.wave.voting_credit_type as ApiWaveCreditType] keeps this header aligned with the rest of the waves UI and avoids leaking raw enum values in the UI. Looks good.

To make this a bit more defensive against unexpected/unknown values coming from the API, you could optionally add a fallback (e.g., to the raw voting_credit_type or a generic label):

{WAVE_VOTING_LABELS[winner.drop.wave.voting_credit_type as ApiWaveCreditType] ??
  winner.drop.wave.voting_credit_type}

Also applies to: 68-69


7-9: Mark props fields as readonly to match guidelines

The props interface currently has a mutable winner field. To align with the guideline of making React props readonly, consider:

interface WaveWinnersDropHeaderVotersProps {
  readonly winner: ApiWaveDecisionWinner;
}
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (1)

7-7: Credit-type label mapping change looks correct and type‑safe

Indexing WAVE_VOTING_LABELS with creditType: ApiWaveCreditType is aligned with the shared constants and keeps the UI text consistent across the app (including new XTDH / TDH+XTDH types). No issues with correctness or typing here; this is a clean UX improvement over showing the raw enum value.

As a separate, non-blocking note: this TSX file still uses plain <img> tags and an inline <svg> icon; per project guidelines and Next.js ESLint rules, consider gradually refactoring these to next/image and FontAwesome icons in a follow-up to keep the file consistent. Based on learnings, this is a recommended refactor rather than a blocker.

Also applies to: 48-48, 80-81

components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (1)

7-7: Consistent, human‑readable vote label usage; implementation is sound

Using WAVE_VOTING_LABELS[creditType] for log.contents.newVote is consistent with the shared wave voting constants and keeps activity log entries in sync with the rest of the UI. Given creditType: ApiWaveCreditType and Record<ApiWaveCreditType, string>, this is type‑safe and should handle the newly added credit types without further changes. The className conditional for green/red remains correct.

Similar to the other sidebar component, this file still uses raw <img> tags and an inline <svg> icon. When convenient, consider refactoring to next/image and FontAwesome icons to better align with the project’s Next.js and UI guidelines. Based on learnings, this is a non‑blocking, recommended cleanup.

Also applies to: 85-89

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

14-15: Consistent voting label mapping; consider extracting a local votingLabel constant

Using WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] keeps this component aligned with the shared label map and avoids hard‑coded strings, which is good.

To avoid repeating the same cast and lookup twice, you could compute it once near the top of the component body:

-    const handleDropClick = useCallback(() => {
+    const votingLabel =
+      WAVE_VOTING_LABELS[
+        drop.wave.voting_credit_type as ApiWaveCreditType
+      ];
+
+    const handleDropClick = useCallback(() => {
       onDropClick(drop);
     }, [drop, onDropClick]);

and then use {votingLabel} in both places. This keeps things a bit cleaner and centralizes the mapping.

Also applies to: 88-89, 107-108

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

16-17: Good use of shared voting labels; you can DRY up the repeated lookup

Switching both spots to WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] correctly reuses the shared label map and keeps display text in sync with other wave views.

As in the default winner component, you could compute this once:

-    const handleDropClick = useCallback(() => {
+    const votingLabel =
+      WAVE_VOTING_LABELS[
+        drop.wave.voting_credit_type as ApiWaveCreditType
+      ];
+
+    const handleDropClick = useCallback(() => {
       onDropClick(drop);
     }, [drop, onDropClick]);

and then render {votingLabel} in both label positions to avoid repeating the cast and lookup.

Also applies to: 90-91, 109-110

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

20-21: Centralized voting label imports are consistent with constants

Importing WAVE_VOTING_LABELS and ApiWaveCreditType matches the shared constants pattern and keeps labels in sync across the app. You might optionally mark ApiWaveCreditType as a type-only import to avoid a runtime binding, but it’s not required.


67-67: Voting credit label lookup with safe fallback

Using WAVE_VOTING_LABELS[winner.drop.wave.voting_credit_type as ApiWaveCreditType] || "votes" correctly routes through the shared mapping while preserving the previous "votes" fallback when the mapping is missing. If you ever allow empty-string labels, consider ?? "votes" instead of ||, but the current code is fine given the existing labels.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 558d20f and 059a538.

📒 Files selected for processing (13)
  • components/drops/view/DropsList.tsx (2 hunks)
  • components/waves/drops/wave-drops-all/index.tsx (1 hunks)
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx (4 hunks)
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx (2 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (2 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (3 hunks)
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx (3 hunks)
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx (3 hunks)
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (4 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (2 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx (2 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx (2 hunks)
  • components/waves/winners/podium/WavePodiumItem.tsx (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • components/waves/drops/wave-drops-all/index.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/drops/view/DropsList.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.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/drops/view/DropsList.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.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/drops/view/DropsList.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.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/drops/view/DropsList.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
🧠 Learnings (2)
📚 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} : Remove unnecessary Effects; if Effect only derives state, compute during render instead

Applied to files:

  • components/drops/view/DropsList.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/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
🧬 Code graph analysis (9)
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/winners/DefaultWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx (2)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
components/waves/winners/podium/WavePodiumItem.tsx (4)
helpers/waves/drop.helpers.ts (1)
  • ExtendedDrop (16-20)
components/utils/tooltip/UserProfileTooltipWrapper.tsx (1)
  • UserProfileTooltipWrapper (12-34)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/winners/podium/WavePodiumItemContentOutcomes.tsx (1)
  • WavePodiumItemContentOutcomes (15-253)
components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx (2)

11-12: LGTM!

The imports for WAVE_VOTING_LABELS and ApiWaveCreditType are correctly added to support the label mapping refactor.


18-124: LGTM!

The refactor to use WAVE_VOTING_LABELS instead of raw voting_credit_type values is consistent and aligns with the centralized label constants pattern introduced in this PR. The component logic remains correct.

components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx (1)

17-18: Imports for voting labels and credit type look correct

Importing WAVE_VOTING_LABELS and ApiWaveCreditType here aligns with the summarized PR changes and keeps the label mapping local to this component. No issues from a typing or structure standpoint.

components/drops/view/DropsList.tsx (1)

42-43: Whitespace-only change is fine

Spacing/blank line adjustments here are non-functional and consistent with surrounding style.

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

3-4: Label mapping is consistent with shared wave voting labels

Switching to WAVE_VOTING_LABELS[winner.drop.wave.voting_credit_type as ApiWaveCreditType] keeps this header consistent with the rest of the wave UI and with the centralized enum→label mapping. The change is clear and type‑safe given the shared ApiWaveCreditType enum.

Also applies to: 39-40

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

10-11: Tooltip voting label matches shared mapping and other winner views

Using WAVE_VOTING_LABELS[winner.drop.wave.voting_credit_type as ApiWaveCreditType] in the tooltip aligns this display with the rest of the wave components and the centralized constants. The change is small, self‑contained, and improves consistency of what users see for voting credits.

Also applies to: 52-53

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

6-9: Drop helper import usage looks correct

Bringing in both ExtendedDrop and convertApiDropToExtendedDrop keeps the prop type and conversion helper aligned; no issues here.


113-116: ClassName conditional formatting remains valid

The multi-line template for the positive/negative vote color is syntactically correct and preserves the intended Tailwind classes; no functional change beyond readability.

components/waves/winners/podium/WavePodiumItem.tsx (4)

11-12: LGTM!

The new imports for WAVE_VOTING_LABELS and ApiWaveCreditType are correctly added and properly used to replace hardcoded credit type strings with centralized constants.


236-238: Verify type safety of the credit type lookup.

The type assertion as ApiWaveCreditType bypasses TypeScript's type checking. If drop.wave.voting_credit_type contains an unexpected value, the lookup will return undefined.

Consider adding a fallback or validating the type:

-                    {WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType]}
+                    {WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] ?? drop.wave.voting_credit_type}

201-226: Good implementation of the user profile tooltip.

The UserProfileTooltipWrapper is correctly applied with proper fallback (drop.author.handle ?? drop.author.id). Click propagation is properly stopped to prevent triggering the parent's onDropClick.


228-254: LGTM!

Good refactoring to use centralized WAVE_VOTING_LABELS instead of hardcoded strings. The conditional color for negative ratings, proper pluralization of "voter"/"voters", and click propagation handling are all correctly implemented.

Comment thread components/drops/view/DropsList.tsx Outdated
Comment thread components/waves/winners/podium/WavePodiumItem.tsx
Comment thread components/waves/winners/podium/WavePodiumItem.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

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

125-133: Replace raw <img> with next/image Image component

The avatar currently uses a plain <img>, which conflicts with the project guideline to use next/image and aligns with @next/next/no-img-element rule recommendations. You can keep the same URI helper and Tailwind classes while migrating to Image:

+import Image from "next/image";
@@
-              {drop.author.pfp ? (
-                <img
-                  src={getScaledImageUri(
-                    drop.author.pfp,
-                    ImageScale.W_AUTO_H_50
-                  )}
-                  alt={`${drop.author.handle}'s profile`}
-                  className="tw-size-7 tw-rounded-lg tw-ring-1 tw-ring-white/10 tw-object-cover"
-                />
+              {drop.author.pfp ? (
+                <Image
+                  src={getScaledImageUri(
+                    drop.author.pfp,
+                    ImageScale.W_AUTO_H_50
+                  )}
+                  alt={`${drop.author.handle}'s profile`}
+                  width={28}
+                  height={28}
+                  className="tw-size-7 tw-rounded-lg tw-ring-1 tw-ring-white/10 tw-object-cover"
+                />
+              ) : (

Width/height 28 matches tw-size-7 sizing. Note: DefaultWaveWinnerDropSmall.tsx has the identical pattern and should be fixed similarly.

🧹 Nitpick comments (11)
components/waves/drop/SingleWaveDropVoter.tsx (1)

45-46: Replace <img> with <Image /> from next/image.

Per coding guidelines, use next/image for images to satisfy the @next/next/no-img-element ESLint rule.

+import Image from "next/image";
...
           {voter.voter.pfp ? (
-            <img src={voter.voter.pfp} alt="" className={pfpClasses} />
+            <Image src={voter.voter.pfp} alt="" width={24} height={24} className={pfpClasses} />
           ) : (
components/waves/drop/SingleWaveDropVoteSlider.tsx (3)

19-21: Remove placeholder comment.

Lines 19-21 appear to be leftover placeholder text that should be removed.

-// ... existing code ...
-
-

23-27: Remove unused PresetMark interface.

Per the AI summary, preset marks logic was removed, but this interface remains as dead code.

-interface PresetMark {
-  percentage: number;
-  label: string;
-  position: number;
-}

134-136: Missing dependency in useEffect.

The x motion value should be included in the dependency array to satisfy react-hooks/exhaustive-deps. Since x is a stable ref from useMotionValue, adding it won't cause re-runs but will satisfy the linter.

   useEffect(() => {
     x.set(currentPercentage);
-  }, [currentPercentage]);
+  }, [currentPercentage, x]);
components/waves/drop/SingleWaveDropVoteInput.tsx (2)

27-32: Hoist static arrays outside the component.

memeticValues, quickPercentages, and mobileQuickPercentages are constant arrays that don't depend on props or state. Defining them inside the component causes unnecessary recreation on every render.

+const MEMETIC_VALUES: number[] = [
+  -69420, -42069, -6529, -420, -69, 69, 420, 6529, 42069, 69420,
+];
+const QUICK_PERCENTAGES = [-100, -75, -50, -25, 25, 50, 75, 100];
+const MOBILE_QUICK_PERCENTAGES = [-75, -50, -25, 25, 50, 75];
+
 export const SingleWaveDropVoteInput: React.FC<
   SingleWaveDropVoteInputProps
 > = ({
   ...
 }) => {
-    const memeticValues: number[] = [
-      -69420, -42069, -6529, -420, -69, 69, 420, 6529, 42069, 69420,
-    ];
-
-    const quickPercentages = [-100, -75, -50, -25, 25, 50, 75, 100];
-    const mobileQuickPercentages = [-75, -50, -25, 25, 50, 75];

Then update references from memeticValues to MEMETIC_VALUES, quickPercentages to QUICK_PERCENTAGES, and mobileQuickPercentages to MOBILE_QUICK_PERCENTAGES.


237-274: Consider using FontAwesome for consistency.

Per coding guidelines, FontAwesome should be used for icons in React components. The inline SVGs work but differ from the pattern used elsewhere (e.g., faExchange in SingleWaveDropVoteContent.tsx).

import { faArrowUp, faArrowDown } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";

// Then replace SVGs with:
<FontAwesomeIcon icon={faArrowUp} className="tw-w-4 tw-h-4 tw-flex-shrink-0" />
<FontAwesomeIcon icon={faArrowDown} className="tw-w-4 tw-h-4 tw-flex-shrink-0" />
components/waves/winners/podium/WavePodiumItem.tsx (1)

29-29: Improved but consider conditional pattern for maximum compatibility.

The hoverTextColor properties now contain complete static variant strings (e.g., "desktop-hover:hover:tw-text-[#fbbf24]"), which should be detected by Tailwind's scanner since they exist as literals in the source. This is a significant improvement over runtime variant construction.

However, the past review recommended using conditional helper functions that return complete static strings (similar to DefaultWaveLeaderboardDrop.tsx) for maximum compatibility. The current interpolation pattern ${styles.hoverTextColor} should work, but the conditional approach eliminates any potential edge cases with Tailwind's scanner.

If you prefer to align with the recommended pattern:

const getHoverColorClass = (position: "first" | "second" | "third") => {
  const colorMap = {
    first: "desktop-hover:hover:tw-text-[#fbbf24]",
    second: "desktop-hover:hover:tw-text-[#94a3b8]",
    third: "desktop-hover:hover:tw-text-[#CD7F32]",
  };
  return colorMap[position];
};

Then use: className={... ${getHoverColorClass(position)} ...}

Also applies to: 52-52, 75-75, 210-210, 212-212

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

16-17: Guard voting label lookup with a fallback to preserve robustness

Deriving votingLabel from WAVE_VOTING_LABELS is the right direction for consistency, but the hard cast to ApiWaveCreditType means any unexpected/legacy voting_credit_type will yield undefined and render as empty text where we previously showed the raw value.

To keep behavior resilient while still using the label map, consider a nullish-coalescing fallback:

-import { WAVE_VOTING_LABELS } from "@/helpers/waves/waves.constants";
-import { ApiWaveCreditType } from "@/generated/models/ApiWaveCreditType";
+import { WAVE_VOTING_LABELS } from "@/helpers/waves/waves.constants";
+import { ApiWaveCreditType } from "@/generated/models/ApiWaveCreditType";-    const votingLabel = WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType];
+    const votingLabel =
+      WAVE_VOTING_LABELS[drop.wave.voting_credit_type as ApiWaveCreditType] ??
+      drop.wave.voting_credit_type ??
+      "";

This keeps the new labeling while ensuring we still show something sensible in both the main rating line and the “You” line if an unknown credit type appears. Please double-check that drop.wave.voting_credit_type’s runtime values always match ApiWaveCreditType or that this fallback matches your domain expectations.

Also applies to: 58-59, 92-93, 110-112

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

28-28: Centralized vote stat labels look good; consider mapping creditType for consistency

Using WAVE_VOTE_STATS_LABELS.TOTAL and WAVE_VOTE_STATS_LABELS.YOUR_VOTES standardizes the copy and aligns this drop view with other vote UIs. One optional improvement: consider deriving a human‑readable label via WAVE_VOTING_LABELS (as in other components) instead of rendering the raw creditType value, so the unit text stays fully consistent across the app.

Also applies to: 176-183, 232-239

components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (1)

5-5: Avatar next/image usage and voting label mapping are on point

Switching the voter avatar to next/image with explicit dimensions and handle‑based alt is solid, and using WAVE_VOTING_LABELS[creditType] keeps the unit text aligned with the global wave voting labels. If you want full consistency with other components later, you could also centralize the trailing "total" string via the same stats label constants you’re using elsewhere, but this isn’t blocking.

Also applies to: 8-8, 32-38, 83-84

components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (1)

2-2: Tooltip identity/avatars and voting labels are wired correctly

Resolving pfp via useSeizeConnectContext/useAuth/useIdentity and rendering it with next/image in the “Your Voting Power” header personalizes the tooltip without changing behavior, and using WAVE_VOTING_LABELS[drop.wave.voting_credit_type] for both the Voting Range and Voted lines keeps the units in sync with the rest of the waves voting UI. If you touch this again, you could optionally cache that label in a local const to avoid repeating the lookup, but it’s not required.

Also applies to: 8-8, 10-12, 26-37, 82-98, 107-107, 111-115

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 059a538 and 14d6d0f.

📒 Files selected for processing (22)
  • components/drops/view/DropsList.tsx (3 hunks)
  • components/waves/drop/SingleWaveDropVoteContent.tsx (9 hunks)
  • components/waves/drop/SingleWaveDropVoteInput.tsx (2 hunks)
  • components/waves/drop/SingleWaveDropVoteSlider.tsx (7 hunks)
  • components/waves/drop/SingleWaveDropVoteStats.tsx (1 hunks)
  • components/waves/drop/SingleWaveDropVoter.tsx (3 hunks)
  • components/waves/drop/SingleWaveDropVotes.tsx (5 hunks)
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (4 hunks)
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx (6 hunks)
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx (3 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (5 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (4 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx (2 hunks)
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx (4 hunks)
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx (4 hunks)
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (4 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (3 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx (2 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx (2 hunks)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.tsx (2 hunks)
  • components/waves/winners/podium/WavePodiumItem.tsx (9 hunks)
  • helpers/waves/create-wave.validation.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • components/waves/winners/drops/header/WaveWinnersDropHeaderTotalVotes.tsx
  • components/waves/leaderboard/drops/header/WaveleaderboardDropRaters.tsx
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoter.tsx
  • components/waves/drop/SingleWaveDropVotes.tsx
  • components/waves/drop/SingleWaveDropVoteStats.tsx
  • components/drops/view/DropsList.tsx
  • components/waves/winners/DefaultWaveWinnerDropSmall.tsx
  • helpers/waves/create-wave.validation.ts
  • components/waves/winners/drops/header/WaveWinnersDropHeaderVoters.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/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx
  • components/waves/drop/SingleWaveDropVoteContent.tsx
  • components/waves/winners/drops/DefaultWaveWinnerDrop.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
🧠 Learnings (12)
📚 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/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx
  • components/waves/drop/SingleWaveDropVoteContent.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/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.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/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.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/podium/WavePodiumItem.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.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/podium/WavePodiumItem.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/podium/WavePodiumItem.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/podium/WavePodiumItem.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/waves/winners/podium/WavePodiumItem.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/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.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/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.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/drop/SingleWaveDropVoteInput.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} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • components/waves/drop/SingleWaveDropVoteContent.tsx
🧬 Code graph analysis (8)
components/waves/winners/drops/MemesWaveWinnerDrop.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTE_STATS_LABELS (15-18)
components/waves/drop/SingleWaveDropVoter.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (2)
  • WAVE_VOTING_LABELS (20-25)
  • WAVE_VOTE_STATS_LABELS (15-18)
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (2)
helpers/Helpers.ts (1)
  • formatNumberWithCommas (103-120)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteContent.tsx (2)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteStats.tsx (1)
  • SingleWaveDropVoteStats (12-41)
components/waves/winners/drops/DefaultWaveWinnerDrop.tsx (1)
helpers/waves/waves.constants.ts (2)
  • WAVE_VOTING_LABELS (20-25)
  • WAVE_VOTE_STATS_LABELS (15-18)
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteSlider.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 (16)
components/waves/drop/SingleWaveDropVoter.tsx (2)

7-7: LGTM - Label constants integration.

The import and usage of WAVE_VOTING_LABELS and WAVE_VOTE_STATS_LABELS aligns with the PR's goal of centralizing voting labels across the codebase.


92-94: LGTM - Proper label usage.

The display text now correctly uses mapped labels (WAVE_VOTING_LABELS[creditType]) and constants (WAVE_VOTE_STATS_LABELS.TOTAL) instead of raw enum values.

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

95-103: LGTM - Label prop usage.

The component correctly receives and uses the label prop in the tooltip display, replacing the previous creditType approach.

Also applies to: 253-253

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

33-35: LGTM - Defensive label computation.

The fallback to "votes" handles cases where voting_credit_type might be undefined or an unexpected value, providing resilient UI behavior.


37-39: LGTM - Dependency update.

The useEffect now correctly depends on currentVoteValue to sync the local state when the prop changes.


77-85: LGTM - Consistent label prop forwarding.

Both MINI and NORMAL layouts correctly pass label={voteLabel} to SingleWaveDropVoteSlider, maintaining consistency across size variants.

Also applies to: 163-170

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

59-73: LGTM - Timer handling refactored correctly.

The timer refs are now properly typed with ReturnType<typeof setInterval/setTimeout> | null, the clearTimers helper properly clears both refs, and the startPress/stopPress functions correctly manage the isPressed flag. The cleanup effect ensures timers are cleared on unmount. This addresses the issues from the previous review.

Also applies to: 133-156


75-131: Verify memetic crossing behavior.

The memetic value crossing logic now uses isPressed.current to determine whether to restart the interval after the 1-second pause. Please verify this provides the expected user experience where:

  1. Crossing a memetic value pauses at that value for 1 second
  2. If the user is still pressing, the interval resumes
  3. If the user releases during the pause, no further updates occur

182-186: LGTM - Keyboard submission support.

The handleKeyDown handler enables form submission via Enter key, improving accessibility and UX.

components/waves/winners/podium/WavePodiumItem.tsx (3)

163-173: LGTM! Image component properly implemented.

The migration from <img> to <Image> from next/image is correct, with proper width and height props. This addresses the previous review concern and satisfies the @next/next/no-img-element ESLint rule.


176-231: Well-structured badge and author section.

The decorative position badge with SVG icon and the tooltip-wrapped author link are well-implemented. Proper accessibility attributes (aria-hidden="true") and click propagation handling (stopPropagation) are in place.


233-260: Clean implementation of rating and voters display.

The use of WAVE_VOTING_LABELS for consistent labeling, proper singular/plural handling for voters, and appropriate click propagation management are all well-executed. The conditional color for negative ratings is a nice UX touch.

components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoters.tsx (1)

7-8: Clock icon migration to FontAwesome is clean and consistent

Using FontAwesomeIcon with faClock in the empty-state block keeps icon usage consistent with the rest of the app and avoids inline SVG duplication; no behavioral changes introduced.

Also applies to: 42-45

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

20-21: Voting unit and “Your votes” labeling are correctly centralized

creditType now comes from WAVE_VOTING_LABELS with a "votes" fallback, and the “Your votes” label uses WAVE_VOTE_STATS_LABELS.YOUR_VOTES, which keeps winner drops in line with the new global voting label strategy without changing behavior.

Also applies to: 67-67, 110-116

components/waves/leaderboard/gallery/WaveLeaderboardGalleryItem.tsx (1)

17-18: Gallery vote labels now use shared mappings consistently

Deriving votingCreditLabel from WAVE_VOTING_LABELS (with a safe fallback) and prefixing the user line with WAVE_VOTE_STATS_LABELS.YOUR_VOTES makes the gallery item’s vote text consistent with the rest of the waves UI without altering vote logic.

Also applies to: 94-96, 193-194

components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarActivityLog.tsx (1)

7-10: Activity log icons, avatars, and vote units are modernized correctly

Replacing the inline clock SVG with FontAwesomeIcon, migrating both avatars to next/image with fixed dimensions, and rendering vote units via WAVE_VOTING_LABELS[creditType] cleanly align this sidebar log with the shared icon and voting label patterns, without changing the underlying vote/change semantics.

Also applies to: 32-35, 54-59, 80-84, 94-99

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

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

128-136: Replace <img> avatar with Next.js <Image> to satisfy ESLint and optimize loading

This component uses a raw <img> for the author avatar, which violates the @next/next/no-img-element ESLint rule and misses image optimization. Replace with <Image> from next/image:

+import Image from "next/image";
@@
-              {drop.author.pfp ? (
-                <img
-                  src={getScaledImageUri(
-                    drop.author.pfp,
-                    ImageScale.W_AUTO_H_50
-                  )}
-                  alt={`${drop.author.handle}'s profile`}
-                  className="tw-size-7 tw-rounded-lg tw-ring-1 tw-ring-white/10 tw-object-cover"
-                />
+              {drop.author.pfp ? (
+                <Image
+                  src={getScaledImageUri(
+                    drop.author.pfp,
+                    ImageScale.W_AUTO_H_50
+                  )}
+                  alt={`${drop.author.handle}'s profile`}
+                  width={28}
+                  height={28}
+                  className="tw-size-7 tw-rounded-lg tw-ring-1 tw-ring-white/10 tw-object-cover"
+                />
🧹 Nitpick comments (5)
components/waves/winners/podium/WavePodiumItem.tsx (1)

220-222: Consider removing duplicate hover class on nested element.

The hoverTextColorClass is applied to both the <Link> (line 220) and the inner <span> (line 222). Since the span inherits text color from its parent, applying it only to the Link should suffice.

                   className={`tw-transition-all tw-no-underline tw-mb-2 tw-mt-2 sm:tw-mt-4 tw-relative tw-text-center ${hoverTextColorClass} tw-group/link`}
                 >
-                  <span className={`${styles.autorFontSize} tw-font-semibold tw-text-iron-200 ${hoverTextColorClass} tw-transition-colors tw-inline-flex tw-items-center`}>
+                  <span className={`${styles.autorFontSize} tw-font-semibold tw-text-iron-200 tw-transition-colors tw-inline-flex tw-items-center`}>
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)

16-17: Voting label mapping and fallbacks are sound; consider extracting a typed helper

Using WAVE_VOTING_LABELS with a ?? fallback to drop.wave.voting_credit_type and then "" is a good, robust way to keep the UI readable even for unknown or missing credit types.

The only minor concern is the as ApiWaveCreditType assertion on drop.wave.voting_credit_type: if that field’s type ever drifts from ApiWaveCreditType, TypeScript will no longer protect you. To keep this pattern type‑safe and reusable across components, consider moving the logic into a helper like getWaveVotingLabel(votingCreditType: ApiWaveCreditType | null | undefined): string in helpers/waves/waves.constants.ts and calling that here instead of asserting. Based on learnings, this would also help keep mapping and fallback behavior centralized.

Also applies to: 58-61

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

36-61: Timer refs and cleanup are structurally sound but may need a hooks-lint tweak

Using separate refs for the interval and pause timeout, plus clearTimers and pressStartTime/isPressed, is a good, type-safe structure and should avoid the earlier mixed-timer issues. startPress/stopPress correctly delegate to clearTimers, and the unmount useEffect ensures timers are torn down.

One thing to watch: useEffect’s cleanup calls clearTimers, but clearTimers is not in the dependency array. react-hooks/exhaustive-deps may flag this. A small refactor would keep ESLint happy without changing behavior:

-import React, { useEffect, useRef } from "react";
+import React, { useCallback, useEffect, useRef } from "react";

-  const clearTimers = () => {
+  const clearTimers = useCallback(() => {
     if (intervalRef.current) {
       clearInterval(intervalRef.current);
       intervalRef.current = null;
     }
     if (pauseTimeoutRef.current) {
       clearTimeout(pauseTimeoutRef.current);
       pauseTimeoutRef.current = null;
     }
-    }
-  };
+    }
+  }, []);

   useEffect(() => {
     return () => {
       clearTimers();
     };
-  }, []);
+  }, [clearTimers]);

This keeps clearTimers stable and eliminates hook-dependency warnings.

Please run ESLint with the React Hooks plugin to confirm whether it currently complains about clearTimers in the effect dependencies.

Also applies to: 149-165, 167-171


128-135: Quick-percentage helpers are coherent; consider edge-case semantics

The quick-percentage logic is consistent between mobile and desktop (MOBILE_QUICK_PERCENTAGES vs QUICK_PERCENTAGES), and the button styling correctly reflects the active percentage via getQuickPercentageButtonClass.

One nuance: for negative percentages, you compute:

percentage < 0
  ? (Math.abs(percentage) / 100) * minValue
  : (percentage / 100) * maxValue;

This assumes minValue is negative when negative percentages are shown. If a future wave config ever used minValue >= 0 (e.g., only long-side voting), negative quick percentages would all map to 0. If that’s possible, you may want to either hide negative quick buttons in that case or derive negative targets symmetrically from the positive side.

Please confirm whether minValue is guaranteed to be negative whenever negative quick percentages are rendered; if not, consider adjusting the mapping or conditionally hiding those buttons.

Also applies to: 272-303

components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (1)

34-37: Consider scaling the user pfp for consistency and performance.

The user's profile picture (line 88) is rendered without scaling, while top voters' profile pictures use getScaledImageUri (lines 54-57). Since both display at 16×16 pixels, applying the same scaling to the user pfp would improve consistency and performance, especially if the source image is large.

Apply this diff to scale the user pfp:

 const pfp = (() => {
-  if (activeProfileProxy) return activeProfileProxy.created_by.pfp;
-  return profile?.pfp ?? null;
+  const rawPfp = activeProfileProxy?.created_by.pfp ?? profile?.pfp ?? null;
+  return rawPfp ? getScaledImageUri(rawPfp, ImageScale.W_AUTO_H_50) : null;
 })();

Also applies to: 85-95

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 14d6d0f and 3e9c014.

📒 Files selected for processing (8)
  • components/waves/drop/SingleWaveDropVoteInput.tsx (6 hunks)
  • components/waves/drop/SingleWaveDropVoteSlider.tsx (8 hunks)
  • components/waves/drop/SingleWaveDropVoter.tsx (4 hunks)
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (5 hunks)
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.tsx (4 hunks)
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx (4 hunks)
  • components/waves/winners/drops/MemesWaveWinnerDrop.tsx (4 hunks)
  • components/waves/winners/podium/WavePodiumItem.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • components/waves/drop/SingleWaveDropVoter.tsx
  • components/waves/leaderboard/sidebar/WaveLeaderboardRightSidebarVoter.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/waves/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.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/winners/drops/MemesWaveWinnerDrop.tsx
  • components/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/winners/MemesWaveWinnerDropSmall.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx
  • components/waves/drop/SingleWaveDropVoteSlider.tsx
🧠 Learnings (9)
📚 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/podium/WavePodiumItem.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/podium/WavePodiumItem.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/podium/WavePodiumItem.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.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/podium/WavePodiumItem.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/waves/winners/podium/WavePodiumItem.tsx
  • components/waves/drop/SingleWaveDropVoteInput.tsx
  • components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.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/podium/WavePodiumItem.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/podium/WavePodiumItem.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/waves/winners/podium/WavePodiumItem.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/drop/SingleWaveDropVoteInput.tsx
🧬 Code graph analysis (2)
components/waves/winners/MemesWaveWinnerDropSmall.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (20-25)
components/waves/drop/SingleWaveDropVoteSlider.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 (18)
components/waves/winners/podium/WavePodiumItem.tsx (5)

1-12: LGTM!

The imports are properly structured. The Image component from next/image addresses the previous review feedback, and WAVE_VOTING_LABELS centralizes voting label management.


118-128: LGTM!

This helper correctly addresses the dynamic Tailwind class detection issue by returning complete static class strings. The as const assertion provides proper type safety.


173-183: LGTM!

The <Image /> component usage is correct. Fetching a 56×56 source and scaling via CSS classes ensures quality across all positions while maintaining proper layout.


251-253: LGTM!

Using WAVE_VOTING_LABELS[drop.wave.voting_credit_type] centralizes the label management and aligns with the PR's objective of consistent voting labels across components.


266-268: LGTM!

Event propagation is handled correctly. The stopPropagation() calls on nested interactive elements prevent unintended triggering of the parent's onDropClick handler.

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

28-32: LGTM! Imports align with centralized label refactoring.

The new imports properly support the centralized voting label pattern being introduced across wave components.


66-69: No issues found. The code is correct: WAVE_VOTING_LABELS is properly typed as Record<ApiWaveCreditType, string> and includes all four enum values (Tdh, Rep, Xtdh, TdhPlusXtdh). The fallback chain provides solid runtime safety.


189-189: WAVE_VOTE_STATS_LABELS constants are properly defined and exported.

The constants TOTAL and YOUR_VOTES are correctly defined in helpers/waves/waves.constants.ts, properly imported in this file, and used correctly at lines 189 and 239.

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

95-95: Consistent use of votingLabel improves UX and avoids leaking raw enum values

Swapping the raw drop.wave.voting_credit_type for the computed votingLabel in both the main rating line and the “You: …” line keeps the wording consistent and human‑readable, and it will automatically pick up future label changes from WAVE_VOTING_LABELS without touching this component.

Also applies to: 115-115

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

9-17: Label prop integration is consistent and type-safe

label is added to the props interface, plumbed through the component signature, and rendered in the tooltip text in a single, consistent way. This matches the PR-wide move from creditType to label-based display with no apparent typing or runtime issues.

Also applies to: 85-93, 236-244


124-127: Motion value sync effect is correctly scoped

Keeping x and currentPercentage in the dependency array ensures the framer-motion value tracks prop-driven changes without extra re-renders. This should satisfy react-hooks/exhaustive-deps while preserving the intended animation behavior.

Please run your lint suite to confirm there are no hook dependency warnings around this effect.


136-143: Layout / hit-area styling adjustments look good

The updated container and track classNames maintain the existing structure while improving touch area and spacing, and they remain Tailwind-only as per guidelines. No behavioral regressions are apparent.

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

3-6: Imports, props, label usage, and icon/UI wiring align with guidelines

  • Uses FontAwesome icons and Tailwind classes exclusively in the JSX.
  • Props interface is readonly and includes the new label string, which is rendered in both MINI and normal layouts.
  • Event handlers (onChange, onKeyDown, press handlers) are wired consistently across input and buttons.

This all matches the repo’s conventions and the PR-wide shift to label-based voting display.

Also applies to: 8-16, 203-220, 224-240, 242-268


136-147: Input parsing and quick-percentage highlighting behavior look robust

  • handleInputChange gracefully handles transient values like "" and "-", only parsing/clamping once a numeric value is available.
  • Clamping via clampValue ensures typed values stay within [minValue, maxValue].
  • getQuickPercentageButtonClass computes targetValue using the same formula as handleQuickPercentage, so the “selected” styling correctly reflects the last clicked quick button even as voteValue changes.

No correctness issues stand out here.

Also applies to: 173-195


62-75: The diagnosis of async state updater semantics is incorrect.

React's state updater functions execute synchronously when setVoteValue(updater) is called. The crossedMemetic flag is assigned within the updater function and the if check evaluates it immediately afterward, before setVoteValue returns. The code should work as intended.

If the memetic pause is not triggering, investigate other causes: (1) whether handleMemeticPause receives the correct increment value in all code paths, (2) whether isPressed.current remains true when the 1s timeout fires, or (3) whether rapid successive updates create race conditions in the pause/resume logic.

The proposed fix introduces an unnecessary Effect that violates React 19.2 guidelines (derive state during render, not in Effects) and does not address the actual issue.

components/waves/drops/participation/ratings/tooltips/VoteBreakdownTooltip.tsx (3)

53-62: LGTM! Top voter avatars properly implemented.

The conversion to next/image is correctly done with descriptive alt text, explicit dimensions, and performance-optimized image scaling. The conditional rendering ensures graceful handling when pfp is missing.


69-74: LGTM! Rating display logic is clear and correct.

The conditional color coding (green for positive, red for negative) paired with the "+" prefix for positive ratings provides clear visual feedback. The formatting correctly handles both positive and negative values.


8-8: This review comment is incorrect. The code is type-safe and will not result in undefined values.

The WAVE_VOTING_LABELS constant is typed as Record<ApiWaveCreditType, string>, which guarantees that all possible ApiWaveCreditType enum values have corresponding string mappings. The enum defines four values (Tdh, Xtdh, TdhPlusXtdh, Rep), and all four are present in WAVE_VOTING_LABELS. TypeScript's type system ensures that indexing into a Record<K, V> with a key of type K always returns V, never undefined. Therefore, votingLabel at line 25 will always be a valid string, and the code at lines 110 and 117 will display the correct label without any risk of showing "undefined".

Likely an incorrect or invalid review comment.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

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

203-222: Add semantic labels for accessibility.

Both input fields lack proper <label> elements or aria-label attributes. The label text (lines 217, 238) is purely visual overlay and not accessible to screen readers, preventing assistive technology users from understanding the purpose of these inputs.

Based on learnings, every form control must have a label using semantic HTML elements.

Apply this diff to add proper labels for the MINI mode:

   if (size === SingleWaveDropVoteSize.MINI) {
     return (
       <div className="tw-flex tw-items-center">
-        <div className="tw-relative tw-w-full tw-h-full">
+        <label className="tw-relative tw-w-full tw-h-full">
           <input
             type="text"
             pattern="-?[0-9]*"
             inputMode="numeric"
             className="tw-w-full tw-px-3 tw-pr-12 tw-h-8 tw-bg-iron-950 tw-rounded-md tw-text-iron-50 tw-placeholder-iron-400 tw-text-base tw-font-medium tw-outline-none tw-border tw-border-solid tw-border-iron-700 desktop-hover:hover:tw-border-primary-400 focus:tw-border-primary-400 tw-transition-all focus:tw-bg-iron-950 tw-duration-300 tw-ease-out"
             value={voteValue}
             onChange={handleInputChange}
             onKeyDown={handleKeyDown}
+            aria-label={`Vote amount in ${label}`}
           />
           <div className="tw-absolute tw-right-3 tw-top-1/2 -tw-translate-y-1/2 tw-text-[11px] tw-text-iron-400 tw-pointer-events-none">
             {label}
           </div>
-        </div>
+        </label>
       </div>
     );
   }

Apply this diff for NORMAL mode:

       <div className="tw-flex tw-items-center tw-gap-2">
-        <div className="tw-relative tw-w-full xl:tw-max-w-xs">
+        <label className="tw-relative tw-w-full xl:tw-max-w-xs">
           <input
             type="text"
             pattern="-?[0-9]*"
             inputMode="numeric"
             className="tw-w-full tw-px-3 tw-pr-24 tw-h-9 tw-bg-iron-900 tw-rounded-lg tw-text-iron-50 tw-placeholder-iron-400 tw-text-base tw-font-medium tw-border-0 tw-ring-1 tw-ring-iron-700 focus:tw-ring-primary-400/50 desktop-hover:hover:tw-ring-primary-400/30 tw-outline-none tw-transition-all desktop-hover:hover:tw-bg-iron-950/60 focus:tw-bg-iron-950/80"
             value={voteValue}
             onChange={handleInputChange}
             onKeyDown={handleKeyDown}
+            aria-label={`Vote amount in ${label}`}
           />
           <div className="tw-absolute tw-right-3 tw-top-1/2 -tw-translate-y-1/2 tw-text-xs tw-text-iron-400 tw-pointer-events-none">
             {label}
           </div>
-        </div>
+        </label>
       </div>

Also applies to: 227-240

🧹 Nitpick comments (2)
components/waves/drop/SingleWaveDropVoteInput.tsx (2)

128-134: Extract duplicate percentage calculation into a shared helper.

The percentage-to-value calculation logic in handleQuickPercentage (lines 129-132) is duplicated in getQuickPercentageButtonClass (lines 177-181). Consider extracting this into a reusable helper function to follow DRY principles.

Apply this diff to extract the shared logic:

+  const calculatePercentageValue = (percentage: number) => {
+    return Math.round(
+      percentage < 0
+        ? (Math.abs(percentage) / 100) * minValue
+        : (percentage / 100) * maxValue
+    );
+  };
+
   const handleQuickPercentage = (percentage: number) => {
-    const value =
-      percentage < 0
-        ? (Math.abs(percentage) / 100) * minValue
-        : (percentage / 100) * maxValue;
-    setVoteValue(Math.round(value));
+    setVoteValue(calculatePercentageValue(percentage));
   };

   const getQuickPercentageButtonClass = (
     percentage: number,
     currentVoteValue: number | string
   ) => {
-    const targetValue = Math.round(
-      percentage < 0
-        ? (Math.abs(percentage) / 100) * minValue
-        : (percentage / 100) * maxValue
-    );
+    const targetValue = calculatePercentageValue(percentage);

     const isSelected = Number(currentVoteValue) === targetValue;
     const isNegative = percentage < 0;

Also applies to: 173-195


243-268: Add accessible labels to arrow buttons.

The increment and decrement arrow buttons lack accessible text, making their purpose unclear to screen reader users. While users can still interact with the input field directly, adding aria-label attributes would improve the experience for assistive technology users.

Apply this diff:

         <button
           onMouseDown={() => startPress(true)}
           onMouseUp={stopPress}
           onMouseLeave={stopPress}
           onTouchStart={() => startPress(true)}
           onTouchEnd={stopPress}
+          aria-label={`Increase ${label}`}
           className="tw-border-0 tw-flex tw-items-center tw-justify-center tw-size-9 tw-rounded-lg tw-bg-iron-900 tw-ring-1 tw-ring-iron-800 desktop-hover:hover:tw-ring-emerald-400/50 tw-text-emerald-400 desktop-hover:hover:tw-text-emerald-300 tw-transition-all tw-duration-300 desktop-hover:hover:tw-scale-105 desktop-hover:hover:tw-bg-iron-800/90 active:tw-scale-95"
         >
           <FontAwesomeIcon
             icon={faArrowUp}
             className="tw-w-4 tw-h-4 tw-flex-shrink-0"
           />
         </button>
         <button
           onMouseDown={() => startPress(false)}
           onMouseUp={stopPress}
           onMouseLeave={stopPress}
           onTouchStart={() => startPress(false)}
           onTouchEnd={stopPress}
+          aria-label={`Decrease ${label}`}
           className="tw-border-0 tw-flex tw-items-center tw-justify-center tw-size-9 tw-rounded-lg tw-bg-iron-900 tw-ring-1 tw-ring-iron-800 desktop-hover:hover:tw-ring-rose-400/50 tw-text-rose-400 desktop-hover:hover:tw-text-rose-300 tw-transition-all tw-duration-300 desktop-hover:hover:tw-scale-105 desktop-hover:hover:tw-bg-iron-800/90 active:tw-scale-95"
         >
           <FontAwesomeIcon
             icon={faArrowDown}
             className="tw-w-4 tw-h-4 tw-flex-shrink-0"
           />
         </button>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e9c014 and d025a50.

📒 Files selected for processing (1)
  • components/waves/drop/SingleWaveDropVoteInput.tsx (6 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/SingleWaveDropVoteInput.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/SingleWaveDropVoteInput.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/SingleWaveDropVoteInput.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/SingleWaveDropVoteInput.tsx
🧠 Learnings (3)
📚 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/drop/SingleWaveDropVoteInput.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/waves/drop/SingleWaveDropVoteInput.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/drop/SingleWaveDropVoteInput.tsx
⏰ 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 (5)
components/waves/drop/SingleWaveDropVoteInput.tsx (5)

3-5: LGTM!

The imports follow best practices with direct named imports from React and FontAwesome icons as specified in the coding guidelines.


8-16: LGTM!

The change from creditType to label makes the component more flexible and decoupled from the API type system. All props correctly use readonly as required.


18-39: LGTM!

The module-level constants and ref types are correctly implemented. The timer refs use ReturnType<typeof setInterval/setTimeout> | null for proper cross-platform type safety, addressing the concerns from previous reviews.


41-109: LGTM!

The helper functions are well-structured and correctly implement the memetic-snapping logic. The approach of checking isPressed.current in the timeout callback eliminates the need for a separate pause state, resulting in cleaner code than the originally suggested implementation.


149-171: LGTM!

The press/release handlers and cleanup effect are correctly implemented. Timers are properly managed, and the cleanup effect ensures no memory leaks on unmount.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
helpers/waves/waves.constants.ts (2)

14-17: Solid centralization of vote stats labels; consider tightening types with as const.

The new WAVE_VOTE_STATS_LABELS keys/values look good and will help keep labels consistent. For slightly stronger typing and to avoid accidental value changes, you could mark this as immutable:

-export const WAVE_VOTE_STATS_LABELS = {
-  YOUR_VOTES: "Your votes",
-  TOTAL: "Total",
-};
+export const WAVE_VOTE_STATS_LABELS = {
+  YOUR_VOTES: "Your votes",
+  TOTAL: "Total",
+} as const;

20-23: Labels for new credit types look correct; consider enforcing enum coverage via satisfies.

The updated WAVE_VOTING_LABELS entries for Tdh, Xtdh, TdhPlusXtdh, and Rep look consistent with the naming elsewhere. To catch missing/extra ApiWaveCreditType members at compile time, you could switch to satisfies:

-export const WAVE_VOTING_LABELS: Record<ApiWaveCreditType, string> = {
-  [ApiWaveCreditType.Tdh]: "TDH",
-  [ApiWaveCreditType.Xtdh]: "XTDH",
-  [ApiWaveCreditType.TdhPlusXtdh]: "TDH + XTDH",
-  [ApiWaveCreditType.Rep]: "Rep",
-};
+export const WAVE_VOTING_LABELS = {
+  [ApiWaveCreditType.Tdh]: "TDH",
+  [ApiWaveCreditType.Xtdh]: "XTDH",
+  [ApiWaveCreditType.TdhPlusXtdh]: "TDH + XTDH",
+  [ApiWaveCreditType.Rep]: "Rep",
+} satisfies Record<ApiWaveCreditType, string>;

Also, please double‑check that every ApiWaveCreditType value that can appear from the API is included here so you never render undefined labels at runtime.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d025a50 and 8026236.

📒 Files selected for processing (1)
  • helpers/waves/waves.constants.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{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:

  • helpers/waves/waves.constants.ts
**/*.{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:

  • helpers/waves/waves.constants.ts
**/*.{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:

  • helpers/waves/waves.constants.ts
🔇 Additional comments (1)
helpers/waves/waves.constants.ts (1)

152-156: No functional change detected in CREATE_WAVE_START_DATE_LABELS.

The modification here appears to be non-functional (likely formatting or a regenerated line ending); no action needed.

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
components/waves/create-wave/voting/CreateWaveVoting.tsx (1)

14-19: Ordering map is redundant without a sort; consider simplifying iteration

VOTING_TYPES_ORDER encodes numeric order but the render logic only filters on !== undefined and then relies on object key insertion order. If someone later changes the numeric values expecting them to control UI order, nothing will happen.

To make the intent explicit and reduce complexity, you can either:

  • Drive the UI from an ordered list, or
  • Keep the map but sort by the numeric order.

For example, an ordered list keeps things simple and avoids the Object.keys cast:

-const VOTING_TYPES_ORDER: Record<ApiWaveCreditType, number | undefined> = {
-  [ApiWaveCreditType.TdhPlusXtdh]: 0,
-  [ApiWaveCreditType.Tdh]: 1,
-  [ApiWaveCreditType.Rep]: 2,
-  [ApiWaveCreditType.Xtdh]: undefined,
-};
+const ORDERED_VOTING_TYPES: readonly ApiWaveCreditType[] = [
+  ApiWaveCreditType.TdhPlusXtdh,
+  ApiWaveCreditType.Tdh,
+  ApiWaveCreditType.Rep,
+];

@@
-        {(
-          Object.keys(VOTING_TYPES_ORDER) as ApiWaveCreditType[]
-        ).filter((votingType) => VOTING_TYPES_ORDER[votingType] !== undefined).map((votingType) => (
+        {ORDERED_VOTING_TYPES.map((votingType) => (

This still hides ApiWaveCreditType.Xtdh from the UI but makes the intended order explicit and easier to maintain.

Also applies to: 65-67

__tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx (1)

14-24: Add test coverage for the new "TDH + xTDH" mode.

The test correctly includes the inclusion_strategy property, but only tests the Tdh mode. Consider adding a test case for ApiGroupTdhInclusionStrategy.Both to verify the label displays as "TDH + xTDH at least".

Add a test case:

it('passes correct label for Both inclusion strategy', () => {
  const setTDH = jest.fn();
  const tdh = { min: 5, inclusion_strategy: ApiGroupTdhInclusionStrategy.Both } as any;
  const { getByTestId } = render(<GroupCreateTDH tdh={tdh} setTDH={setTDH} />);
  expect(getByTestId('numeric')).toBeInTheDocument();
  expect(mockProps.value).toBe(5);
  expect(mockProps.label).toBe('TDH + xTDH at least');
});
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8026236 and bfe7e8f.

📒 Files selected for processing (7)
  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx (2 hunks)
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts (2 hunks)
  • components/groups/page/create/GroupCreate.tsx (1 hunks)
  • components/groups/page/create/config/GroupCreateTDH.tsx (1 hunks)
  • components/waves/create-wave/hooks/useWaveConfig.ts (1 hunks)
  • components/waves/create-wave/voting/CreateWaveVoting.tsx (2 hunks)
  • helpers/waves/create-wave.helpers.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (12)
**/*.{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/groups/page/create/GroupCreate.tsx
  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • components/groups/page/create/config/GroupCreateTDH.tsx
  • components/waves/create-wave/hooks/useWaveConfig.ts
  • helpers/waves/create-wave.helpers.ts
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
  • components/waves/create-wave/voting/CreateWaveVoting.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/groups/page/create/GroupCreate.tsx
  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • components/groups/page/create/config/GroupCreateTDH.tsx
  • components/waves/create-wave/voting/CreateWaveVoting.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/groups/page/create/GroupCreate.tsx
  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • components/groups/page/create/config/GroupCreateTDH.tsx
  • components/waves/create-wave/hooks/useWaveConfig.ts
  • helpers/waves/create-wave.helpers.ts
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
  • components/waves/create-wave/voting/CreateWaveVoting.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/groups/page/create/GroupCreate.tsx
  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • components/groups/page/create/config/GroupCreateTDH.tsx
  • components/waves/create-wave/hooks/useWaveConfig.ts
  • helpers/waves/create-wave.helpers.ts
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
  • components/waves/create-wave/voting/CreateWaveVoting.tsx
{.env*,*.env,**/config/**}

📄 CodeRabbit inference engine (.cursor/rules/dev_workflow.mdc)

Configure Task Master behavior via environment variables: ANTHROPIC_API_KEY (required), MODEL, MAX_TOKENS, TEMPERATURE, DEBUG, LOG_LEVEL, DEFAULT_SUBTASKS, DEFAULT_PRIORITY, PROJECT_NAME, PROJECT_VERSION, PERPLEXITY_API_KEY, and PERPLEXITY_MODEL

Files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • components/groups/page/create/config/GroupCreateTDH.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/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

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

Files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (GEMINI.md)

Mock external dependencies and APIs in tests

Files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
__tests__/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use Jest + ts-jest for TypeScript testing

Files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
__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/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
__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/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
__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/groups/page/create/config/GroupCreateTDH.test.tsx
  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
🧠 Learnings (7)
📚 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/groups/page/create/config/GroupCreateTDH.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/groups/page/create/config/GroupCreateTDH.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 **/*.test.{ts,tsx} : Mock external dependencies and APIs in tests

Applied to files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.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__/app/api/**/__tests__/**/*.test.{ts,tsx,js} : API integration tests should be located in `app/api`

Applied to files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.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__/**/components/**/*.test.{ts,tsx} : Use testing-library/react + user-event for React component tests

Applied to files:

  • __tests__/components/groups/page/create/config/GroupCreateTDH.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} : Avoid double negatives in code; prefer explicit logic and remove redundant annotations; use optional chaining (`?.`)

Applied to files:

  • __tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts
📚 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/create-wave/hooks/useWaveConfig.test.ts
🧬 Code graph analysis (2)
__tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts (1)
components/waves/create-wave/hooks/useWaveConfig.ts (1)
  • useWaveConfig (27-358)
components/waves/create-wave/voting/CreateWaveVoting.tsx (1)
helpers/waves/waves.constants.ts (1)
  • WAVE_VOTING_LABELS (19-24)
🔇 Additional comments (6)
helpers/waves/create-wave.helpers.ts (1)

375-383: Defaulting voting credit_type to TdhPlusXtdh matches the new wave semantics

Using config.voting.type ?? ApiWaveCreditType.TdhPlusXtdh is a clean way to make TDH + XTDH the explicit default while still honoring any configured credit type. This is consistent with the PR’s intent and keeps the payload well-defined even if config.voting.type is unset.

components/waves/create-wave/voting/CreateWaveVoting.tsx (1)

73-73: Label composition looks consistent with shared voting labels

The new label={By ${WAVE_VOTING_LABELS[votingType]}} usage cleanly centralizes the human-readable text and should stay in sync with WAVE_VOTING_LABELS (including the new TDH + XTDH entry). No issues here.

components/groups/page/create/config/GroupCreateTDH.tsx (1)

15-26: LGTM! Mode consolidation is consistent.

The updated modes array with "TDH + xTDH" (Both) and "TDH" (Tdh) options is correctly implemented, and the display logic at lines 35-43 and 62-65 properly handles the Both case by showing "TDH + xTDH" labels.

components/waves/create-wave/hooks/useWaveConfig.ts (1)

71-71: LGTM! Default voting type updated to TDH + XTDH.

The change from ApiWaveCreditType.Tdh to ApiWaveCreditType.TdhPlusXtdh as the default voting configuration aligns with the broader PR changes introducing combined TDH + XTDH voting.

components/groups/page/create/GroupCreate.tsx (1)

99-99: LGTM! Default updated with backward compatibility maintained.

The change to default new groups to ApiGroupTdhInclusionStrategy.Both is consistent with the PR objectives. Backward compatibility is correctly preserved at lines 134-136 where existing groups maintain their original inclusion_strategy or default to Tdh if not present.

__tests__/components/waves/create-wave/hooks/useWaveConfig.test.ts (1)

49-60: LGTM! Test expectations correctly updated.

The test description and assertions have been properly updated to reflect the new default voting type of ApiWaveCreditType.TdhPlusXtdh, matching the implementation changes in useWaveConfig.ts.

@sonarqubecloud
Copy link
Copy Markdown

@simo6529 simo6529 merged commit bbd96d1 into main Dec 16, 2025
8 checks passed
@simo6529 simo6529 deleted the xtdh-voting branch December 16, 2025 10:41
@coderabbitai coderabbitai Bot mentioned this pull request Dec 19, 2025
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