Skip to content

lint errors#1586

Merged
simo6529 merged 17 commits intomainfrom
lint-errors-v2
Nov 5, 2025
Merged

lint errors#1586
simo6529 merged 17 commits intomainfrom
lint-errors-v2

Conversation

@simo6529
Copy link
Copy Markdown
Collaborator

@simo6529 simo6529 commented Oct 30, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved pagination/infinite-scroll across feeds and direct messages.
    • Better loading/error feedback across downloads and distribution plan flows.
    • Stronger vote input validation to avoid invalid submissions.
    • More reliable wallet actions with clearer failure alerts.
  • Refactor

    • Stabilized ENS/address resolution and delegation flows for more reliable address handling.
    • Reduced UI flicker and rerenders; removed external active-item highlighting.
    • Streamlined distribution plan snapshot handling and broader pool support.
  • Style

    • Copy action updated to a consistent icon.

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

coderabbitai Bot commented Oct 30, 2025

Walkthrough

Stabilizes callbacks, adds sentinel-based IntersectionObserver pagination, extracts a reusable ENS resolution hook, migrates several fetch flows to react-query, tightens/marks many props as readonly/optional with defaults, replaces an inline copy icon with FontAwesome, and makes eslint react-compiler plugin load conditional.

Changes

Cohort / File(s) Summary
App wallets
components/app-wallets/AppWallet.tsx, components/app-wallets/AppWalletsContext.tsx
Switched a catch (_error) to a bare catch and memoized wallet CRUD/fetch functions with useCallback.
Copy icon
components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
Replaced inline SVG copy icon with FontAwesomeIcon (faCopy) and removed unused copy state.
Sentinel pagination & waves/DMs
components/brain/direct-messages/DirectMessagesList.tsx, components/brain/left-sidebar/waves/UnifiedWavesList.tsx, components/brain/left-sidebar/web/WebUnifiedWavesList.tsx, components/brain/left-sidebar/waves/BrainLeftSidebarWaves.tsx, __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx, components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
Replaced prior intersection logic with sentinel-based IntersectionObserver using useEffectEvent, memoized list derivation, adjusted observer lifecycle, and removed activeWaveId prop from UnifiedWavesList and callers/tests.
Feed observer
components/brain/feed/FeedScrollContainer.tsx
Replaced repeated observedFeedItemsRef.current access with a local Map reference and updated init/cleanup; effect now depends on [ref].
My stream & votes
components/brain/my-stream/*.tsx, components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
Added memoization, fixed dependencies, derived editing state from values, improved input parsing/blur/submit validation and error handling.
Notifications
components/brain/notifications/NotificationsFollowBtn.tsx
Removed synced local following state; derive following and label directly from profile.subscribed_actions.
Community features
components/community-downloads/CommunityDownloadsComponent.tsx, components/community/CommunityMembers.tsx, components/community/members-table/CommunityMembersTableHeaderSortableContent.tsx
Migrated manual fetch/state to useQuery, added memoized callbacks/memos, expanded effect dependencies.
Cookie consent
components/cookies/CookieConsentContext.tsx
Wrapped cookie consent and GTM loader logic in useCallback and tied init effect to memoized getter.
Delegation area
components/delegation/** (many files)
Large refactors: added helpers, guarded early returns, replaced inline ENS/address handling with useEnsResolution, adopted react-query in places, reworked effects/dependencies, removed/renamed helpers.
New ENS hook
hooks/useEnsResolution.ts
New useEnsResolution hook exposing inputValue, address, setters/handlers and ENS queries (ensNameQuery, ensAddressQuery) with input normalization.
WalletChecker
components/delegation/walletChecker/WalletChecker.tsx
Moved to useEnsResolution, added react-query useQueries, derived memoized state, and normalized consolidation display/flows.
Distribution plan / build phases
components/distribution-plan-tool/** (many files)
Removed/simplified unique-wallets-count logic, added/expanded react-query usage, introduced typed prop interfaces and defaults/optionals, broadened some Pool typings, and removed some UI/meta blocks.
Distribution plan warnings & meta
components/distribution-plan-tool/common/DistributionPlanWarnings.tsx, components/distribution-plan-tool/.../ComponentConfigMeta.tsx
Simplified logic by removing local state/effects and reduced rendered UI surface.
SelectSnapshot / Pool typing
components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsx, .../SelectSnapshotDropdownListItem.tsx
Broadened onSelectSnapshot snapshotType to Pool; added handling for Pool.WALLET_POOL subtitle.
ESLint config
eslint.config.mjs
Dynamically attempts to load eslint-plugin-react-compiler, conditionally registers plugin/rules, and expands global ignore patterns.
Misc / tests & typing tweaks
__tests__/**, various components/**
Many props marked readonly/optional with defaults, removed unused helpers/vars, updated tests to match prop removals/defaults, and minor UI/class/icon tweaks.

Sequence Diagram(s)

sequenceDiagram
    participant View as Viewport/User
    participant Sentinel as IntersectionObserver Sentinel
    participant DMList as DirectMessagesList
    participant Fetch as fetchNextPage

    rect rgb(235,245,255)
    Note over DMList: Sentinel-based pagination (useEffectEvent)
    end

    View->>Sentinel: sentinel enters viewport
    Sentinel->>DMList: intersection callback
    DMList->>DMList: fetchNextPageIfNeeded (useEffectEvent)
    alt can fetch
        DMList->>Fetch: call fetchNextPage()
        Fetch-->>DMList: page data
        DMList->>DMList: append list, update fetching flags
    else blocked/already fetching
        DMList->>DMList: no-op
    end
Loading
sequenceDiagram
    participant WalletChecker as WalletChecker
    participant ENSHook as useEnsResolution
    participant DelegQuery as Delegation API (react-query)
    participant ConsQuery as Consolidation API (react-query)

    rect rgb(235,250,240)
    Note over WalletChecker: ENS resolution + react-query-driven fetches
    end

    WalletChecker->>ENSHook: handleInputChange(value)
    ENSHook-->>WalletChecker: address / ensName results
    WalletChecker->>DelegQuery: trigger delegations query (enabled if address)
    WalletChecker->>ConsQuery: trigger consolidations query (guarded)
    DelegQuery-->>WalletChecker: delegations data
    ConsQuery-->>WalletChecker: consolidation data
    WalletChecker->>WalletChecker: compute derived active/recommendations (useMemo)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files/areas needing extra attention:
    • components/delegation/CollectionDelegation.tsx — extensive guard and effect dependency changes.
    • components/delegation/walletChecker/WalletChecker.tsx — large refactor to react-query + ENS hook and normalization.
    • hooks/useEnsResolution.ts — new hook with ENS queries and input normalization behavior.
    • components/brain/direct-messages/DirectMessagesList.tsx and components/brain/left-sidebar/waves/UnifiedWavesList.tsx — sentinel pagination and useEffectEvent integration.
    • distribution-plan-tool component-config files — many signature/prop-default changes and removed unique-wallets counting logic.

Possibly related PRs

Suggested reviewers

  • prxt6529

Poem

🐇 I hopped through code with a twitch and a stitch,

ENS names now tidy, callbacks snug in their niche,
Sentinels wake when the viewport says "roll",
Icons swapped, defaults neat — components stroll,
A rabbit’s small refactor, neat as a twitch. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'lint errors' is vague and generic, using a non-descriptive term that does not convey meaningful information about the changeset's primary objective. Replace the generic title with a more descriptive phrase that captures the main focus, such as 'Refactor wallet and delegation components with memoization and hook consolidation' or identify the most critical change across the 40+ files modified.
✅ 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 lint-errors-v2

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

Caution

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

⚠️ Outside diff range comments (13)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx (1)

22-58: Remove commented-out code.

The guidelines require no comments in TypeScript/React files. This entire commented-out JSX block should be removed rather than retained in version control.

Apply this diff:

  return (
    <div className="tw-space-y-1 tw-self-center">
-     {/* <div className="tw-flex tw-space-x-2">
-       {tags.map((tag) => (
-         <span
-           key={tag.id}
-           className="tw-font-normal tw-text-primary-400 tw-text-xs tw-truncate group-hover:tw-text-neutral-400 tw-transition tw-duration-300 tw-ease-out"
-         >
-           {tag.name}
-         </span>
-       ))}
-     </div>
-     <div className="tw-text-xs tw-space-x-2">
-       <span className="tw-text-neutral-400 tw-font-light">
-         Total wallets:
-       </span>
-       {!isLoading ? (
-         <span className="tw-font-normal">{walletsCount ?? "N/A"}</span>
-       ) : (
-         <svg
-           aria-hidden="true"
-           role="status"
-           className="tw-inline tw-w-5 tw-h-5 tw-text-primary-400 tw-animate-spin tw-absolute"
-           viewBox="0 0 100 101"
-           fill="none"
-           xmlns="http://www.w3.org/2000/svg"
-         >
-           <path
-             className="tw-text-neutral-600"
-             d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
-             fill="currentColor"
-           ></path>
-           <path
-             d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
-             fill="currentColor"
-           ></path>
-         </svg>
-       )}
-     </div> */}
    </div>
  );

As per coding guidelines: "Do not include any comments in the code".

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (2)

24-40: Missing readonly modifier on props object; unused config prop in destructuring.

The component's props object is missing the readonly keyword as per coding guidelines. Additionally, the config property is declared in the type definition but is not destructured from the function parameters, making it unused.

Apply this diff to add readonly and remove the unused config:

 export default function SnapshotExcludeComponentWinners({
   phases,
   onNextStep,
   onSelectExcludeComponentWinners,
   title,
   onClose,
-}: {
-  config: PhaseGroupSnapshotConfig;
-  phases: BuildPhasesPhase[];
-  onNextStep: (step: PhaseConfigStep) => void;
-  onSelectExcludeComponentWinners: (param: {
-    excludeComponentWinners: string[];
-    uniqueWalletsCount: number | null;
-  }) => void;
-  title: string;
-  onClose: () => void;
+}: readonly {
+  phases: readonly BuildPhasesPhase[];
+  onNextStep: (step: PhaseConfigStep) => void;
+  onSelectExcludeComponentWinners: (param: {
+    excludeComponentWinners: string[];
+    uniqueWalletsCount: number | null;
+  }) => void;
+  title: string;
+  onClose: () => void;
 }) {

137-186: Remove large block of commented-out code.

This commented-out useEffect block violates the coding guideline: "Do not include any comments in the code." Remove it entirely rather than keeping it as a comment.

Apply this diff to remove the commented code:

-  // useEffect(() => {
-  //   const getCustomTokenPoolWallets = (): string[] => {
-  //     const operation = operations.find(
-  //       (o) =>
-  //         o.code === AllowlistOperationCode.CREATE_CUSTOM_TOKEN_POOL &&
-  //         o.params.id === config.snapshotId
-  //     );
-  //     if (!operation) {
-  //       return [];
-  //     }
-
-  //     return operation.params.tokens.map((t: any) => t.owner.toLowerCase());
-  //   };
-
-  //   const fetchUniqueWalletsCount = async () => {
-  //     if (!excludeComponentWinners.length) {
-  //       setLocalUniqueWalletsCount(config.uniqueWalletsCount);
-  //       return;
-  //     }
-  //     if (!distributionPlan || !config.snapshotType) return;
-  //     const extraWallets =
-  //       config.snapshotType === Pool.CUSTOM_TOKEN_POOL
-  //         ? getCustomTokenPoolWallets()
-  //         : [];
-  //     setLoading(true);
-  //     const endpoint = `/allowlists/${distributionPlan.id}/token-pool-downloads/token-pool/${config.snapshotId}/unique-wallets-count`;
-  //     const { success, data } = await distributionPlanApiPost<number>({
-  //       endpoint,
-  //       body: {
-  //         excludeComponentWinners,
-  //         excludeSnapshots: config.excludeSnapshots,
-  //         extraWallets,
-  //       },
-  //     });
-  //     if (!success) {
-  //       setLoading(false);
-  //       return { success: false };
-  //     }
-  //     setLocalUniqueWalletsCount(data);
-  //     setLoading(false);
-  //     return { success: true };
-  //   };
-  //   fetchUniqueWalletsCount();
-  // }, [
-  //   excludeComponentWinners,
-  //   distributionPlan,
-  //   config,
-  //   setToasts,
-  //   operations,
-  // ]);
components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx (1)

9-11: Add readonly modifier to props per coding guidelines.

The props should have the readonly modifier as per the coding guidelines for TypeScript files.

As per coding guidelines.

Apply this diff:

 }: {
-  snapshotId: string | null;
-  snapshotType: Pool | null;
+  readonly snapshotId: string | null;
+  readonly snapshotType: Pool | null;
 }) {
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

134-176: Remove commented-out code.

This large commented-out block violates the coding guideline: "Do not include any comments in the code." If this functionality needs to be restored later, it can be retrieved from version control history.

As per coding guidelines.

Apply this diff to remove the commented code:

-  // useEffect(() => {
-  //   const getCustomTokenPoolWallets = (): string[] => {
-  //     const operation = operations.find(
-  //       (o) =>
-  //         o.code === AllowlistOperationCode.CREATE_CUSTOM_TOKEN_POOL &&
-  //         o.params.id === config.snapshotId
-  //     );
-  //     if (!operation) {
-  //       return [];
-  //     }
-
-  //     return operation.params.tokens.map((t: any) => t.owner.toLowerCase());
-  //   };
-
-  //   const fetchUniqueWalletsCount = async () => {
-  //     if (!snapshotsToExclude.length) {
-  //       setLocalUniqueWalletsCount(config.uniqueWalletsCount);
-  //       return;
-  //     }
-  //     if (!distributionPlan || !config.snapshotType) return;
-  //     const extraWallets =
-  //       config.snapshotType === Pool.CUSTOM_TOKEN_POOL
-  //         ? getCustomTokenPoolWallets()
-  //         : [];
-  //     setLoading(true);
-  //     const endpoint = `/allowlists/${distributionPlan.id}/token-pool-downloads/token-pool/${config.snapshotId}/unique-wallets-count`;
-  //     const { success, data } = await distributionPlanApiPost<number>({
-  //       endpoint,
-  //       body: {
-  //         excludeComponentWinners: [],
-  //         excludeSnapshots: snapshotsToExclude,
-  //         extraWallets,
-  //       },
-  //     });
-  //     setLoading(false);
-  //     if (!success) {
-  //       return { success: false };
-  //     }
-  //     setLocalUniqueWalletsCount(data);
-  //     return { success: true };
-  //   };
-  //   fetchUniqueWalletsCount();
-  // }, [config, distributionPlan, snapshotsToExclude, setToasts, operations]);
-
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (4)

711-726: Remove or restore broken state chain.

The state variables uniqueWalletsCountByOperations and loadingUniqueWalletsCountIds are passed to child components (lines 922-923, 934-935, 944-945, 959-960), but their setters are prefixed with underscores and never called. This means:

  • uniqueWalletsCountByOperations is always null
  • loadingUniqueWalletsCountIds is always an empty array
  • isLoadingUniqueWalletsCount is set once to false and never changes
  • The useEffect on lines 720-726 serves no purpose

This appears to be incomplete refactoring. Either:

  1. Remove the unused state variables and stop passing them to child components, or
  2. Restore the functionality from the commented code (lines 791-844) if the feature is still needed

780-789: Remove unused debounced state.

The state variable _debouncedUniqueCountOps is computed via useDebounce but never read. Since the functionality it supported has been commented out (line 798 in the commented block), this state and its debounce effect should be removed.

Apply this diff:

-  const [_debouncedUniqueCountOps, setDebouncedUniqueCountOps] = useState<
-    AllowlistOperationBase[]
-  >([]);
-  useDebounce(
-    () => {
-      setDebouncedUniqueCountOps(uniqueCountOps);
-    },
-    1000,
-    [uniqueCountOps]
-  );

791-844: Remove commented code.

The large commented-out block violates the coding guideline: "Do not include any comments in the code." If this functionality might be needed in the future, it's preserved in version control history.

As per coding guidelines.

Apply this diff:

-  // useEffect(() => {
-  //   const getUniqueWalletsCount = async (distributionPlanId: string) => {
-  //     const endpoint = `/allowlists/${distributionPlanId}/unique-wallets-count`;
-  //     const uniqueId = getRandomObjectId();
-  //     setLoadingUniqueWalletsCountIds((ids) => [...ids, uniqueId]);
-  //     const { success, data } = await distributionPlanApiPost<number>({
-  //       endpoint,
-  //       body: debouncedUniqueCountOps,
-  //     });
-  //     if (!success) {
-  //       setLoadingUniqueWalletsCountIds((ids) =>
-  //         ids.filter((id) => id !== uniqueId)
-  //       );
-  //       return { success: false };
-  //     }
-  //     setUniqueWalletsCountByOperations(data);
-  //     setLoadingUniqueWalletsCountIds((ids) =>
-  //       ids.filter((id) => id !== uniqueId)
-  //     );
-  //     return { success: true };
-  //   };
-
-  //   if (!distributionPlan) {
-  //     setUniqueWalletsCountByOperations(null);
-  //     return;
-  //   }
-
-  //   if (isAddingOperations) {
-  //     return;
-  //   }
-
-  //   if (
-  //     ![
-  //       PhaseConfigStep.FINALIZE_SNAPSHOT,
-  //       PhaseConfigStep.COMPONENT_ADD_SPOTS,
-  //       PhaseConfigStep.FINALIZE_COMPONENTS,
-  //     ].includes(configStep)
-  //   ) {
-  //     return;
-  //   }
-
-  //   if (debouncedUniqueCountOps.length < 0) {
-  //     setUniqueWalletsCountByOperations(null);
-  //     return;
-  //   }
-
-  //   getUniqueWalletsCount(distributionPlan.id);
-  // }, [
-  //   distributionPlan,
-  //   setToasts,
-  //   configStep,
-  //   debouncedUniqueCountOps,
-  //   isAddingOperations,
-  // ]);

98-110: Add readonly modifiers to props.

Per the coding guideline "Always add readonly before props" for **/*.{ts,tsx} files, the component props should use an interface with readonly properties.

As per coding guidelines.

Apply this diff to extract and add readonly modifiers:

+interface BuildPhaseFormConfigModalProps {
+  readonly name: string;
+  readonly description: string;
+  readonly selectedPhase: BuildPhasesPhase;
+  readonly phases: BuildPhasesPhase[];
+  readonly onClose: () => void;
+}
+
 export default function BuildPhaseFormConfigModal({
   name,
   description,
   selectedPhase,
   phases,
   onClose,
-}: {
-  name: string;
-  description: string;
-  selectedPhase: BuildPhasesPhase;
-  phases: BuildPhasesPhase[];
-  onClose: () => void;
-}) {
+}: BuildPhaseFormConfigModalProps) {
components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (3)

28-39: Fix type safety violation allowing invalid vote submission.

The input handler allows voteValue to be set to "" or "-" using an as any cast (line 32), bypassing TypeScript's type safety. This creates a critical bug:

  1. When voteValue is "" or "-", the submit button becomes enabled (since "" !== 0)
  2. Clicking submit passes this string value to the API as a rate (line 86)
  3. The API expects a number, causing a runtime error

Apply this diff to fix the type safety issue:

 const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
   const inputValue = e.target.value;
 
-  if (inputValue === "" || inputValue === "-") {
-    setVoteValue(inputValue as any);
+  if (inputValue === "") {
+    setVoteValue(currentVoteValue);
+    return;
+  }
+
+  if (inputValue === "-") {
     return;
   }
 
   const value = parseInt(inputValue);
   if (isNaN(value)) return;
   setVoteValue(Math.min(Math.max(value, minRating), maxRating));
 };

41-65: Parameter rename follows convention; consider removing comments per guidelines.

The rename of the parameter to _response (line 50) correctly indicates it's intentionally unused, following common convention.

However, the coding guidelines specify "Do not include any comments in the code" for TypeScript files. Consider removing the comments on lines 51 and 58.

Apply this diff to align with coding guidelines:

   onSuccess: (_response: ApiDrop) => {
-    // Show success toast
     setToast({
       message: "Vote updated",
       type: "success",
     });
   },
   onError: (error) => {
-    // Show error toast
     setToast({
       message: error as unknown as string,
       type: "error",
     });
     throw error;
   },

67-97: Parameter rename follows convention; consider removing comments per guidelines.

The rename of the error parameter to _error (line 88) correctly indicates it's intentionally unused, following common convention.

However, the coding guidelines specify "Do not include any comments in the code" for TypeScript files. Consider removing the comments on lines 72 and 89.

Apply this diff to align with coding guidelines:

   setIsProcessing(true);
 
-  // Show loading message via button state (the button will show loading state)
   try {
     const { success } = await requestAuth();
     if (!success) {
-      // Show authentication error
       setToast({
         message: "Authentication failed",
         type: "error",
     rate: voteValue,
   });
 } catch (_error) {
-  // Any errors not caught in mutation will be handled here
   setToast({
     message: "Something went wrong",
     type: "error",
components/delegation/CollectionDelegation.tsx (1)

265-274: Bug: incoming delegations query never fires when list is empty.

useReadContracts stays disabled for everyone with zero incoming delegations, so the hook never polls and those users can’t see new delegations appear. Drop the length guard so the query always runs while connected.

   query: {
-    enabled: accountResolution.isConnected && incomingDelegations.length > 0,
+    enabled: accountResolution.isConnected,
     refetchInterval: 10000,
   },
♻️ Duplicate comments (2)
components/delegation/DelegationCenter.tsx (1)

18-18: Verify useEffectEvent availability in your React version.

useEffectEvent is an experimental API that is not yet part of stable React. This import may fail at runtime if your React version doesn't include it.

See the same issue flagged in components/delegation/UpdateDelegation.tsx at line 3.

components/delegation/walletChecker/WalletChecker.tsx (1)

73-112: Extract ENS resolution logic into a shared hook.

The ENS resolution logic here is duplicated in UpdateDelegation.tsx and DelegationFormParts.tsx. This code should be extracted into a shared hook to improve maintainability.

See the same issue flagged in components/delegation/DelegationFormParts.tsx at lines 38-80.

🧹 Nitpick comments (14)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)

131-131: Replace static loading state with constant.

The loading state is initialized to false and never updated elsewhere in the component. This should be simplified to a constant rather than state.

Apply this diff to replace the state with a constant:

-  const [loading] = useState<boolean>(false);
+  const loading = false;
components/community-downloads/CommunityDownloadsComponent.tsx (1)

58-61: Consider memoizing the setPage callback.

The inline arrow function creates a new instance on every render, potentially causing unnecessary re-renders of the Pagination component.

Apply this diff to memoize the callback:

+  const handlePageChange = useCallback((newPage: number) => {
+    setPage(newPage);
+    window.scrollTo(0, 0);
+  }, []);
+
   return (
     <DownloadsLayout title={props.title}>
       ...
       <Pagination
         page={page}
         pageSize={PAGE_SIZE}
         totalResults={totalResults}
-        setPage={(newPage: number) => {
-          setPage(newPage);
-          window.scrollTo(0, 0);
-        }}
+        setPage={handlePageChange}
       />

Add useCallback to the imports on line 3:

-import { useState, useEffect } from "react";
+import { useState, useEffect, useCallback } from "react";
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (2)

43-47: Consider making poolTypeToString a constant outside the component.

This mapping never changes, so using useState adds unnecessary overhead. Define it as a plain constant outside the component instead.

Apply this diff:

+const POOL_TYPE_TO_STRING: Record<Pool, string> = {
+  [Pool.CUSTOM_TOKEN_POOL]: "Custom Snapshot",
+  [Pool.TOKEN_POOL]: "Snapshot",
+  [Pool.WALLET_POOL]: "Wallets",
+};
+
 export default function SnapshotExcludeOtherSnapshots({
   snapshots,
   config,
   onSkip,
   onSelectExcludeOtherSnapshots,
   title,
   onClose,
 }: {
   snapshots: DistributionPlanSnapshot[];
   config: PhaseGroupSnapshotConfig;
   onSkip: () => void;
   onSelectExcludeOtherSnapshots: (param: {
     snapshotsToExclude: PhaseGroupSnapshotConfigExcludeSnapshot[];
     uniqueWalletsCount: number | null;
   }) => void;
   title: string;
   onClose: () => void;
 }) {
   const { operations, setToasts } = useContext(DistributionPlanToolContext);
 
-  const [poolTypeToString] = useState<Record<Pool, string>>({
-    [Pool.CUSTOM_TOKEN_POOL]: "Custom Snapshot",
-    [Pool.TOKEN_POOL]: "Snapshot",
-    [Pool.WALLET_POOL]: "Wallets",
-  });
+  const poolTypeToString = POOL_TYPE_TO_STRING;

Then update the dependency array on line 130:

-  }, [selectedOptions, operations, setToasts, poolTypeToString]);
+  }, [selectedOptions, operations, setToasts]);

119-119: Replace any type with proper typing.

Using any for the token parameter reduces type safety.

Consider defining a proper type for tokens or extracting the owner property with better typing.

components/brain/my-stream/MyStreamWaveDesktopTabs.tsx (1)

188-188: Consider memoizing the options array to prevent unnecessary effect runs.

The dependency array is correct for the lint rule. However, since options (lines 168-178) is recalculated on every render, this effect will run on every render. While the guard condition prevents issues, memoizing options with useMemo would improve performance by preventing unnecessary effect executions.

Consider wrapping the options calculation in useMemo:

-  const options: TabOption[] = availableTabs
-    .filter(
-      (tab) =>
-        isMemesWave ||
-        ![MyStreamWaveTab.MY_VOTES, MyStreamWaveTab.FAQ].includes(tab)
-    )
-    .map((tab) => ({
-      key: tab,
-      label: tabLabels[tab],
-      panelId: getContentTabPanelId(tab),
-    }));
+  const options: TabOption[] = React.useMemo(
+    () =>
+      availableTabs
+        .filter(
+          (tab) =>
+            isMemesWave ||
+            ![MyStreamWaveTab.MY_VOTES, MyStreamWaveTab.FAQ].includes(tab)
+        )
+        .map((tab) => ({
+          key: tab,
+          label: tabLabels[tab],
+          panelId: getContentTabPanelId(tab),
+        })),
+    [availableTabs, isMemesWave]
+  );
components/brain/my-stream/MyStreamWaveFAQ.tsx (1)

33-35: Remove unnecessary memoization for static string.

The useMemo hook provides no benefit here since it computes a static string that never changes. This adds unnecessary overhead without any performance gain.

Apply this diff to simplify the code:

-  const containerClassName = useMemo(() => {
-    return "tw-w-full tw-flex tw-flex-col tw-pt-4 lg:tw-pr-2 tw-overflow-y-auto no-scrollbar lg:tw-scrollbar-thin tw-scrollbar-thumb-iron-500 tw-scrollbar-track-iron-800 desktop-desktop-hover:hover:desktop-hover:hover:tw-scrollbar-thumb-iron-300 tw-h-full";
-  }, []);
+  const containerClassName = "tw-w-full tw-flex tw-flex-col tw-pt-4 lg:tw-pr-2 tw-overflow-y-auto no-scrollbar lg:tw-scrollbar-thin tw-scrollbar-thumb-iron-500 tw-scrollbar-track-iron-800 desktop-desktop-hover:hover:desktop-hover:hover:tw-scrollbar-thumb-iron-300 tw-h-full";

Alternatively, if you prefer to keep it semantic, move it outside the component:

+const CONTAINER_CLASS_NAME = "tw-w-full tw-flex tw-flex-col tw-pt-4 lg:tw-pr-2 tw-overflow-y-auto no-scrollbar lg:tw-scrollbar-thin tw-scrollbar-thumb-iron-500 tw-scrollbar-track-iron-800 desktop-desktop-hover:hover:desktop-hover:hover:tw-scrollbar-thumb-iron-300 tw-h-full";
+
 const MyStreamWaveFAQ: React.FC<MyStreamWaveFAQProps> = ({ wave: _wave }) => {
   const { setActiveContentTab } = useContentTab();
   const { faqViewStyle } = useLayout();

   useEffect(() => {
     setActiveContentTab(MyStreamWaveTab.FAQ);
   }, [setActiveContentTab]);

-  const containerClassName = useMemo(() => {
-    return "tw-w-full tw-flex tw-flex-col tw-pt-4 lg:tw-pr-2 tw-overflow-y-auto no-scrollbar lg:tw-scrollbar-thin tw-scrollbar-thumb-iron-500 tw-scrollbar-track-iron-800 desktop-desktop-hover:hover:desktop-hover:hover:tw-scrollbar-thumb-iron-300 tw-h-full";
-  }, []);

   return (
-    <div className={containerClassName} style={faqViewStyle}>
+    <div className={CONTAINER_CLASS_NAME} style={faqViewStyle}>
components/delegation/NewAssignPrimaryAddress.tsx (1)

117-122: Consider using the areEqualAddresses helper.

The validation logic manually converts addresses to uppercase for comparison. The codebase already provides areEqualAddresses (imported at line 14) for this purpose.

Apply this diff:

     } else if (
-      (subdelegation &&
-        selectedToAddress.toUpperCase() ===
-          subdelegation.originalDelegator.toUpperCase()) ||
-      (!subdelegation &&
-        selectedToAddress.toUpperCase() === address.toUpperCase())
+      (subdelegation &&
+        areEqualAddresses(selectedToAddress, subdelegation.originalDelegator)) ||
+      (!subdelegation &&
+        areEqualAddresses(selectedToAddress, address))
components/brain/left-sidebar/waves/UnifiedWavesList.tsx (1)

28-28: Unused prop: activeWaveId is destructured but never used.

The prop is aliased to _activeWaveId but never referenced in the component. If this prop is not needed, consider removing it from the interface, or document why it must remain for API compatibility.

components/brain/left-sidebar/web/WebUnifiedWavesList.tsx (1)

26-26: Unused prop: activeWaveId is destructured but never used.

The prop is aliased to _activeWaveId but never referenced in the component. If this prop is not needed, consider removing it from the interface, or document why it must remain for API compatibility.

components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (1)

49-62: Use FontAwesome instead of inline SVG.

The coding guidelines specify that FontAwesome should be used for icons in .tsx files. Consider replacing the inline SVG with a FontAwesome icon such as faCopy from @fortawesome/free-regular-svg-icons.

As per coding guidelines.

components/delegation/UpdateDelegation.tsx (2)

71-90: Refactor state update pattern to avoid side effects in callback.

The pattern of capturing updatedAddress from within the setDelegationToInput callback is unconventional. State setter callbacks should be pure functions that compute the next state without side effects.

Consider refactoring to compute the address outside the callback:

-  const appendEnsLabelForAddress = useEffectEvent((ensName: string) => {
-    let updatedAddress: string | null = null;
-
-    setDelegationToInput((currentInput) => {
-      if (
-        !currentInput ||
-        !currentInput.startsWith("0x") ||
-        currentInput.includes(" - ")
-      ) {
-        return currentInput;
-      }
-
-      updatedAddress = currentInput;
-      return `${ensName} - ${currentInput}`;
-    });
-
-    if (updatedAddress) {
-      setDelegationToAddress(updatedAddress);
-    }
-  });
+  const appendEnsLabelForAddress = useEffectEvent((ensName: string) => {
+    setDelegationToInput((currentInput) => {
+      if (
+        !currentInput ||
+        !currentInput.startsWith("0x") ||
+        currentInput.includes(" - ")
+      ) {
+        return currentInput;
+      }
+
+      setDelegationToAddress(currentInput);
+      return `${ensName} - ${currentInput}`;
+    });
+  });

108-136: Consider simplifying the conditional logic for readability.

The function has multiple nested conditionals that make it harder to follow. While functionally correct, the logic could be more readable.

Consider early returns and clearer variable names:

   const appendAddressForEnsLabel = useEffectEvent(
     (resolvedAddress: string) => {
       setDelegationToAddress(resolvedAddress);
 
       setDelegationToInput((currentInput) => {
         if (!currentInput) {
           return currentInput;
         }
 
-        const [label] = currentInput.split(" - ");
-        if (!label) {
+        const parts = currentInput.split(" - ");
+        const label = parts[0];
+        if (!label) {
           return currentInput;
         }
 
         const prefix = `${label} - `;
         const nextValue = `${prefix}${resolvedAddress}`;
 
-        if (currentInput.endsWith(".eth")) {
-          return currentInput === nextValue ? currentInput : nextValue;
-        }
-
-        if (currentInput.startsWith(prefix)) {
+        if (currentInput.endsWith(".eth") || currentInput.startsWith(prefix)) {
           return currentInput === nextValue ? currentInput : nextValue;
         }
 
         return currentInput;
       });
     }
   );
components/delegation/DelegationFormParts.tsx (1)

38-80: Extract ENS resolution logic into a shared hook.

The ENS name and address resolution logic is duplicated across multiple files (UpdateDelegation.tsx, WalletChecker.tsx, and this file). This makes the code harder to maintain and test.

Consider creating a shared hook like useEnsResolution in a file like hooks/useEnsResolution.ts:

export function useEnsResolution(input: string) {
  const [displayValue, setDisplayValue] = useState(input);
  const [address, setAddress] = useState(input);

  // ENS name resolution logic
  // ENS address resolution logic
  
  return { displayValue, address, setDisplayValue };
}

Then use it in components:

const { displayValue, address, setDisplayValue } = useEnsResolution(initialValue);
components/delegation/walletChecker/WalletChecker.tsx (1)

114-221: Consider migrating to react-query for data fetching.

The data fetching logic uses raw fetch via fetchUrl, but the coding guidelines specify using react-query for data fetching in TypeScript/TSX files. React-query would provide benefits like automatic caching, refetching, and loading states.

As per coding guidelines, consider refactoring to use react-query:

import { useQuery } from '@tanstack/react-query';

const { data: delegations, isLoading: delegationsLoading } = useQuery({
  queryKey: ['delegations', walletAddress],
  queryFn: () => fetchUrl(`${publicEnv.API_ENDPOINT}/api/delegations/${walletAddress}`),
  enabled: checking && isValidEthAddress(walletAddress),
});

This would simplify state management and provide better caching/refetching behavior.

Based on coding guidelines.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66468b2 and 712e3a8.

📒 Files selected for processing (30)
  • components/app-wallets/AppWallet.tsx (1 hunks)
  • components/app-wallets/AppWalletsContext.tsx (4 hunks)
  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (1 hunks)
  • components/brain/direct-messages/DirectMessagesList.tsx (3 hunks)
  • components/brain/feed/FeedScrollContainer.tsx (5 hunks)
  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx (5 hunks)
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx (1 hunks)
  • components/brain/my-stream/MyStreamWaveDesktopTabs.tsx (2 hunks)
  • components/brain/my-stream/MyStreamWaveFAQ.tsx (1 hunks)
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (4 hunks)
  • components/brain/notifications/NotificationsFollowBtn.tsx (2 hunks)
  • components/community-downloads/CommunityDownloadsComponent.tsx (1 hunks)
  • components/community/CommunityMembers.tsx (7 hunks)
  • components/community/members-table/CommunityMembersTableHeaderSortableContent.tsx (1 hunks)
  • components/cookies/CookieConsentContext.tsx (6 hunks)
  • components/delegation/CollectionDelegation.tsx (14 hunks)
  • components/delegation/DelegationCenter.tsx (1 hunks)
  • components/delegation/DelegationFormParts.tsx (11 hunks)
  • components/delegation/NewAssignPrimaryAddress.tsx (6 hunks)
  • components/delegation/NewSubDelegation.tsx (0 hunks)
  • components/delegation/UpdateDelegation.tsx (3 hunks)
  • components/delegation/walletChecker/WalletChecker.tsx (7 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx (2 hunks)
  • components/distribution-plan-tool/common/DistributionPlanWarnings.tsx (1 hunks)
  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (2 hunks)
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx (2 hunks)
💤 Files with no reviewable changes (1)
  • components/delegation/NewSubDelegation.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
  • components/brain/feed/FeedScrollContainer.tsx
  • components/delegation/DelegationCenter.tsx
  • components/community/members-table/CommunityMembersTableHeaderSortableContent.tsx
  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx
  • components/brain/notifications/NotificationsFollowBtn.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
  • components/community/CommunityMembers.tsx
  • components/app-wallets/AppWallet.tsx
  • components/distribution-plan-tool/common/DistributionPlanWarnings.tsx
  • components/delegation/UpdateDelegation.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx
  • components/brain/my-stream/MyStreamWaveDesktopTabs.tsx
  • components/app-wallets/AppWalletsContext.tsx
  • components/delegation/CollectionDelegation.tsx
  • components/delegation/NewAssignPrimaryAddress.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/brain/my-stream/MyStreamWaveFAQ.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/DelegationFormParts.tsx
  • components/cookies/CookieConsentContext.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
  • components/brain/feed/FeedScrollContainer.tsx
  • components/delegation/DelegationCenter.tsx
  • components/community/members-table/CommunityMembersTableHeaderSortableContent.tsx
  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx
  • components/brain/notifications/NotificationsFollowBtn.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
  • components/community/CommunityMembers.tsx
  • components/app-wallets/AppWallet.tsx
  • components/distribution-plan-tool/common/DistributionPlanWarnings.tsx
  • components/delegation/UpdateDelegation.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx
  • components/brain/my-stream/MyStreamWaveDesktopTabs.tsx
  • components/app-wallets/AppWalletsContext.tsx
  • components/delegation/CollectionDelegation.tsx
  • components/delegation/NewAssignPrimaryAddress.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/brain/my-stream/MyStreamWaveFAQ.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/DelegationFormParts.tsx
  • components/cookies/CookieConsentContext.tsx
🧠 Learnings (2)
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
PR: 6529-Collections/6529seize-frontend#0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version

Applied to files:

  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
PR: 6529-Collections/6529seize-frontend#0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.tsx : Use FontAwesome for icons

Applied to files:

  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
🧬 Code graph analysis (14)
components/delegation/DelegationCenter.tsx (1)
components/auth/SeizeConnectContext.tsx (1)
  • useSeizeConnectContext (618-626)
components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (1)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/brain/direct-messages/DirectMessagesList.tsx (1)
components/brain/left-sidebar/waves/UnifiedWavesListLoader.tsx (1)
  • UnifiedWavesListLoader (9-30)
components/distribution-plan-tool/common/DistributionPlanWarnings.tsx (2)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/distribution-plan-tool/common/DistributionPlanErrorWarning.tsx (1)
  • DistributionPlanErrorWarning (6-49)
components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (1)
generated/models/ApiDrop.ts (1)
  • ApiDrop (28-227)
components/app-wallets/AppWalletsContext.tsx (2)
components/app-wallets/app-wallet-helpers.ts (1)
  • encryptData (26-42)
helpers/time.ts (1)
  • Time (4-445)
components/delegation/CollectionDelegation.tsx (1)
components/delegation/delegation-constants.ts (1)
  • CONSOLIDATION_USE_CASE (79-83)
components/delegation/NewAssignPrimaryAddress.tsx (3)
components/auth/Auth.tsx (1)
  • AuthContext (83-93)
helpers/Helpers.ts (1)
  • areEqualAddresses (149-154)
components/delegation/DelegationFormParts.tsx (4)
  • DelegationFormOriginalDelegatorFormGroup (131-160)
  • DelegationFormLabel (100-129)
  • DelegationAddressDisabledInput (162-173)
  • DelegationCloseButton (491-519)
components/delegation/walletChecker/WalletChecker.tsx (5)
entities/IDelegation.ts (1)
  • WalletConsolidation (29-36)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
services/6529api.ts (1)
  • fetchUrl (6-19)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
components/delegation/delegation-constants.ts (1)
  • MINTING_USE_CASE (57-60)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (2)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistOperation (133-139)
components/distribution-plan-tool/create-plan/CreatePlan.tsx (2)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistDescription (12-18)
services/distribution-plan-api.ts (1)
  • distributionPlanApiFetch (38-62)
components/community-downloads/CommunityDownloadsComponent.tsx (3)
components/leaderboard/NFTLeaderboard.tsx (1)
  • PAGE_SIZE (27-27)
services/6529api.ts (1)
  • fetchUrl (6-19)
generated/models/ApiUploadsPage.ts (1)
  • ApiUploadsPage (16-56)
components/delegation/DelegationFormParts.tsx (1)
helpers/AllowlistToolHelpers.ts (1)
  • getRandomObjectId (46-48)
🔇 Additional comments (51)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx (1)

15-19: Clarify intent: Component accepts unused props.

The destructured parameters (prefixed with _) are never used in the function body. The component currently accepts ComponentConfigMetaProps but ignores all values and renders only an empty div.

Verify that this is intentional—either the props should be removed from the signature, or the commented implementation should be restored and debugged.

components/distribution-plan-tool/common/DistributionPlanWarnings.tsx (4)

3-3: LGTM! Clean import simplification.

The refactoring successfully removes unused React hooks, keeping only what's necessary for this component.


9-9: LGTM! Efficient context usage.

Destructuring only the required distributionPlan from context is a good practice that reduces unnecessary dependencies.


11-12: LGTM! Excellent refactoring to derived value.

This change eliminates unnecessary state management and side effects by computing hasErrors directly from the current data. The optional chaining properly handles null/undefined cases, and the simple computation doesn't require memoization. This approach is more predictable and easier to maintain.


14-14: LGTM! Clean conditional rendering.

The render logic is straightforward and follows React best practices.

components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (3)

13-15: LGTM! Removed unused context value.

Removing setToasts from the context destructuring is good cleanup since it's not used in this component.


35-45: LGTM! Removed unused response data.

Removing data from the response destructuring is appropriate since only the success boolean is checked and the returned data is not used.


30-58: Verify alignment with data fetching guidelines.

The coding guidelines specify "Use react-query for data fetching," but this component uses direct API calls via the distributionPlanApiPost service.

Please confirm whether:

  1. The guideline applies to mutations (POST operations) or only queries (GET operations)
  2. This pattern is acceptable or if there's a plan to migrate to React Query's useMutation

As per coding guidelines

components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx (2)

1-1: LGTM! Unused import removed.

Removing the unused AllowlistOperationCode import improves code clarity and aligns with the PR's goal of addressing lint errors.


33-33: LGTM! Semicolon added for consistency.

The semicolon addition likely addresses a linting rule and maintains consistency with the codebase style.

components/brain/my-stream/MyStreamWaveDesktopTabs.tsx (1)

142-143: Correct dependency additions.

These dependencies are used within the effect body (lines 133-134), so adding them to the dependency array correctly satisfies the exhaustive-deps lint rule.

components/brain/my-stream/MyStreamWaveFAQ.tsx (1)

25-25: ****

The wave prop with the underscore prefix is correctly implemented. The prop is actively passed by callers (MyStreamWave.tsx, BrainMobile.tsx), so it serves an API consistency purpose. The underscore prefix is the appropriate convention for suppressing the unused variable lint warning while maintaining the component's public interface contract.

components/brain/feed/FeedScrollContainer.tsx (2)

79-79: LGTM! Correct dependency array fix.

Adding ref to the dependency array is correct since the effect uses it internally (lines 53-55, 59, 64, 66). This ensures the MutationObserver is properly reinitialized if the forwarded ref changes, which fixes the React exhaustive-deps lint rule.


93-93: LGTM! Clean refactoring with local reference pattern.

Creating a local reference to the Map (line 93) and using it throughout the effect is a good refactoring that improves readability and ensures consistent access to the same Map instance. All operations (get, set, has, delete, clear) work correctly with this pattern.

Also applies to: 99-99, 105-105, 130-130, 134-134, 139-139, 143-143, 151-151, 180-180, 223-223

components/app-wallets/AppWallet.tsx (1)

122-122: LGTM! Clean removal of unused error variable.

Removing the unused error parameter from the catch clause fixes a lint warning without changing functionality.

components/cookies/CookieConsentContext.tsx (5)

77-93: Proper memoization of DOM manipulation.

The loadPerformanceCookies function is correctly memoized with an empty dependency array since it only manipulates the DOM and references the constant GTM_ID.


95-130: Correct memoization with appropriate dependencies.

The getCookieConsent function is properly memoized with [loadPerformanceCookies] as its only dependency. The recursive call on line 125 is safe since it references the memoized function.


132-145: Dependencies correctly specified.

The consent callback properly includes both getCookieConsent and setToast in its dependency array, ensuring stable behavior while capturing all external references.


147-164: Dependencies correctly specified.

The reject callback properly includes both getCookieConsent and setToast in its dependency array, mirroring the correct pattern used in consent.


171-173: Correct dependency array for useEffect.

Adding getCookieConsent to the dependency array satisfies React Hook rules. Since getCookieConsent is memoized with stable dependencies, this effect will still effectively run only once on mount.

components/app-wallets/AppWalletsContext.tsx (4)

57-70: Correct memoization with minimal dependencies.

The fetchAppWallets function is properly memoized with only [appWalletsSupported] in its dependency array. State setters are stable and correctly excluded.


116-157: Dependencies correctly specified for wallet creation.

The createAppWallet callback properly includes both appWalletsSupported and fetchAppWallets in its dependency array, ensuring the function captures the latest values while remaining stable across renders.


159-201: Dependencies correctly specified for wallet import.

The importAppWallet callback properly includes both appWalletsSupported and fetchAppWallets in its dependency array, mirroring the correct pattern used in createAppWallet.


203-216: Dependencies correctly specified for wallet deletion.

The deleteAppWallet callback properly includes both appWalletsSupported and fetchAppWallets in its dependency array, maintaining consistency with the other wallet operations.

components/community/members-table/CommunityMembersTableHeaderSortableContent.tsx (1)

36-39: Dependency array fix correctly addresses stale closure.

The updated dependency array now includes all values used in the effect body (isActive, hoveringOption, sort), ensuring the rotate state updates correctly when any of these values change.

components/community/CommunityMembers.tsx (8)

7-7: LGTM! Required imports for memoization refactor.


48-61: Good refactor - stabilizes callback reference.

Wrapping convertSortBy in useCallback prevents unnecessary recalculations of the params memoized value.


63-76: Good refactor - stabilizes callback reference.

Consistent with convertSortBy, this memoization prevents unnecessary recalculations downstream.


78-103: Well-structured memoization with complete dependencies.

The useMemo prevents unnecessary query parameter re-derivations, and the dependency array correctly includes all referenced values.


105-119: LGTM! Properly memoized query string builder.

The useCallback with [searchParams] dependency ensures this function reference remains stable unless search params change.


139-141: Lazy initialization pattern applied correctly.

Using a function for initial state is a good practice, though the performance benefit is minimal since params is already memoized.


171-180: Memoization and dependency fixes work together correctly.

The updateFields callback is properly memoized, and the effect at line 206 now includes all its dependencies (activeGroupId, params.group_id, updateFields).

Also applies to: 206-220


222-233: Pagination logic properly memoized with complete dependencies.

Both setPage callback and the pagination effect have correct, exhaustive dependency arrays that ensure proper reactivity without causing unnecessary re-renders.

Also applies to: 237-253

components/brain/notifications/NotificationsFollowBtn.tsx (2)

3-3: LGTM! Removed unused import.

The removal of useEffect is correct since the component now derives values directly from props instead of synchronizing state.


35-36: No action needed—the refactor is safe.

The subscribed_actions field is a required, non-nullable array in the ApiProfileMin schema, so the derived values on lines 35–36 are safe. The code correctly assumes the field always exists and has no runtime error risk.

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

3-3: Good cleanup removing unused import.

The removal of useEffect from the imports is correct since it's no longer used after converting isEditing to a derived value.


26-26: Excellent simplification using derived state.

Converting isEditing from a state variable to a computed value eliminates unnecessary state management and prevents potential synchronization bugs.

components/distribution-plan-tool/create-plan/CreatePlan.tsx (1)

3-30: No action needed—React 19.2.0 confirmed.

The project is already on React 19.2.0, so useEffectEvent is fully supported and available. The import and usage are correct.

components/delegation/NewAssignPrimaryAddress.tsx (3)

45-53: LGTM! Clean prop destructuring.

The destructuring improves readability and the rename to camelCase follows JavaScript conventions.


61-110: LGTM! Consistent use of destructured variables.

The refactor to use destructured variables throughout the component improves code readability and maintainability.

Also applies to: 173-189, 205-206, 243-243, 249-249


149-166: No action required - setAddressQuery from useState is already stable.

The concern is theoretically valid, but doesn't apply in this codebase. The setNewPrimaryAddressQuery prop originates from useState in app/delegation/[...section]/page.client.tsx (line 20), which React guarantees has a stable identity across renders. Including it in the dependency array is correct per exhaustive-deps, and it will not cause performance issues because useState setters are inherently stable—no explicit useCallback wrapping is needed.

components/brain/direct-messages/DirectMessagesList.tsx (2)

33-53: Nice refactoring with useEffectEvent and localized state.

The destructuring of directMessages properties and the use of fetchNextPageIfNeeded with useEffectEvent improves code clarity and correctly excludes the stable callback from the dependency array (line 75). The guard logic inside fetchNextPageIfNeeded also centralizes the fetch conditions well.

Also applies to: 55-75


3-3: No action required. The review comment is incorrect.

React 19.2 (released October 1, 2025) includes useEffectEvent as a stable API, and the project uses React 19.2.0. The import of useEffectEvent is valid and the warning about it being experimental is outdated.

Likely an incorrect or invalid review comment.

components/brain/left-sidebar/waves/UnifiedWavesList.tsx (1)

8-8: useEffectEvent is available in stable React as of October 2025—this review comment is outdated.

React added useEffectEvent to stable React in React 19.2 (released October 1, 2025). Your project uses React 19.2.0, so the code is correct. The usage of useEffectEvent on lines 8 and 43-46 is valid and follows best practices for creating stable function references in dependency arrays.

Likely an incorrect or invalid review comment.

components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (1)

38-38: LGTM: Unused variable removed.

The copyState variable was unused, so ignoring it in the destructuring is the correct approach.

components/delegation/DelegationCenter.tsx (1)

26-60: LGTM: Clean refactor to event-based handlers.

The separation of redirect logic into handleRedirect and handleSeizeConnectClosed event handlers improves code organization and follows React patterns for handling side effects that don't need reactive dependencies.

components/delegation/DelegationFormParts.tsx (2)

300-309: LGTM: Clean destructuring pattern.

Destructuring props at the component start and using local variables throughout improves readability and reduces noise from repeated props. references.


82-84: Review comment is misdirected; parent components are already correct.

Parent components correctly pass stable useState setters (setNewDelegationToAddress) to DelegationFormDelegateAddressFormGroup, so the upstream dependency is stable. However, the actual issue exists at line 281 in DelegationFormDelegateAddressFormGroup:

setAddress={(address: string) => props.setAddress(address)}

This wrapper function is recreated on every render of DelegationFormDelegateAddressFormGroup, causing the effect at lines 82-84 to re-run unnecessarily. The wrapper should be memoized with useCallback or removed entirely by passing props.setAddress directly.

Likely an incorrect or invalid review comment.

components/delegation/walletChecker/WalletChecker.tsx (2)

114-281: LGTM: Solid memoization strategy.

The use of useCallback and useMemo is well-structured:

  • Fetch functions are properly memoized with stable references
  • Derived computations (activeDelegation, consolidationActions) correctly depend on their data sources
  • Dependency arrays are complete and accurate

The consolidation normalization logic handles both primary and reciprocal entries correctly.


310-337: LGTM: Well-structured validation and fetch orchestration.

The main checking effect properly validates the wallet address before proceeding, resets relevant state, and coordinates the data fetching flow. The dependency array is complete and the early returns prevent unnecessary work.

components/delegation/UpdateDelegation.tsx (1)

3-3: No action needed — useEffectEvent is stable in React 19.2.0.

React 19.2 (released October 1, 2025) ships a stable useEffectEvent hook. Your codebase already uses it across multiple components without issues, and it is actively documented as a recommended pattern in your project guidelines.

Likely an incorrect or invalid review comment.

Comment thread components/brain/direct-messages/DirectMessagesList.tsx Outdated
Comment thread components/brain/left-sidebar/waves/UnifiedWavesList.tsx Outdated
Comment thread components/community-downloads/CommunityDownloadsComponent.tsx Outdated
Comment thread components/delegation/NewAssignPrimaryAddress.tsx
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: 5

Caution

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

⚠️ Outside diff range comments (7)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (1)

26-38: Extract props to a readonly type/interface.

The props type definition should use readonly modifiers as per coding guidelines. Extract the inline type to a separate interface with readonly properties.

Apply this refactor:

+interface FinalizeSnapshotProps {
+  readonly onConfigureGroup: () => void;
+  readonly onAddAnotherSnapshot: () => void;
+  readonly onRemoveGroupSnapshot: (groupSnapshotId: string) => void;
+  readonly onStartAgain: () => void;
+  readonly groupSnapshots: PhaseGroupSnapshotConfig[];
+  readonly snapshots: DistributionPlanSnapshot[];
+  readonly title: string;
+  readonly uniqueWalletsCount?: number | null;
+  readonly isLoadingUniqueWalletsCount?: boolean;
+  readonly onClose: () => void;
+  readonly phases: BuildPhasesPhase[];
+}
+
 export default function FinalizeSnapshot({
   onConfigureGroup,
   onAddAnotherSnapshot,
   onRemoveGroupSnapshot,
   onStartAgain,
   groupSnapshots,
   snapshots,
   title,
   uniqueWalletsCount = null,
   isLoadingUniqueWalletsCount = false,
   onClose,
   phases,
-}: {
-  onConfigureGroup: () => void;
-  onAddAnotherSnapshot: () => void;
-  onRemoveGroupSnapshot: (groupSnapshotId: string) => void;
-  onStartAgain: () => void;
-  groupSnapshots: PhaseGroupSnapshotConfig[];
-  snapshots: DistributionPlanSnapshot[];
-  title: string;
-  uniqueWalletsCount?: number | null;
-  isLoadingUniqueWalletsCount?: boolean;
-  onClose: () => void;
-  phases: BuildPhasesPhase[];
-}) {
+}: FinalizeSnapshotProps) {

As per coding guidelines.

components/community-downloads/CommunityDownloadsComponent.tsx (1)

18-21: Add readonly modifiers to interface properties.

The coding guidelines specify "Always add readonly before props". While Readonly<Props> is used at the function parameter level, the interface properties themselves should also be readonly.

As per coding guidelines

Apply this diff:

 interface Props {
-  title: string;
-  url: string;
+  readonly title: string;
+  readonly url: string;
 }
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (1)

46-65: Replace state with derived value.

isDisabled is entirely derived from maxMints and doesn't need to be state. Using useState + useEffect for derived values is an anti-pattern that adds unnecessary complexity and potential for stale state.

Apply this diff to compute isDisabled directly:

-  const [isDisabled, setIsDisabled] = useState<boolean>(false);
-
-  useEffect(() => {
-    if (!maxMints) {
-      setIsDisabled(true);
-      return;
-    }
-
-    if (typeof maxMints !== "number") {
-      setIsDisabled(true);
-      return;
-    }
-
-    if (typeof maxMints === "number" && maxMints < 1) {
-      setIsDisabled(true);
-      return;
-    }
-
-    setIsDisabled(false);
-  }, [maxMints]);
+  const isDisabled = !maxMints || typeof maxMints !== "number" || maxMints < 1;
components/distribution-plan-tool/create-plan/CreatePlan.tsx (1)

17-77: Migrate to react-query for data fetching.

The component uses direct fetch API, but the coding guidelines require using react-query for data fetching. Migrating to react-query would provide automatic loading/error states, caching, retries, and simplify the component logic significantly.

As per coding guidelines.

Consider a refactor like:

const { data, isLoading, error } = useQuery({
  queryKey: ['distributionPlan', id],
  queryFn: () => distributionPlanApiFetch<AllowlistDescription>(`/allowlists/${id}`),
  enabled: !!id,
});

useEffect(() => {
  if (!id) {
    makeErrorToast("No id found");
    router.push("/emma");
    return;
  }
  
  if (error || (data && !data.success)) {
    router.push("/emma");
    return;
  }
  
  if (data?.data) {
    setState(data.data);
  }
}, [id, data, error, setState, router]);

This would eliminate the need for manual cleanup patterns and useEffectEvent.

components/brain/direct-messages/DirectMessagesList.tsx (1)

29-29: Remove comment per coding guidelines.

The coding guidelines specify: "Do not include any comments in the code" for TypeScript files.

Apply this diff:

-  // Moved all hooks to the top level, before any conditional logic
   const listRef = useRef<UnifiedWavesListWavesHandle>(null);
components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx (1)

28-40: Add readonly prefix to props parameter.

As per coding guidelines, props should be marked with readonly.

Apply this diff:

 export default function FinalizeComponent({
   onSave,
   onStartAgain,
   onRemoveGroupSnapshot,
   phaseGroupConfig,
   snapshots,
   loading,
   title,
   uniqueWalletsCount = null,
   isLoadingUniqueWalletsCount = false,
   onClose,
   phases,
-}: {
+}: Readonly<{
   onSave: () => void;
   onStartAgain: () => void;
   onRemoveGroupSnapshot: (groupSnapshotId: string) => void;
   phaseGroupConfig: PhaseGroupConfig;
   snapshots: DistributionPlanSnapshot[];
   loading: boolean;
   title: string;
   uniqueWalletsCount?: number | null;
   isLoadingUniqueWalletsCount?: boolean;
   onClose: () => void;
   phases: BuildPhasesPhase[];
-}) {
+}>) {
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx (1)

28-40: Add readonly prefix to props parameter.

As per coding guidelines, props should be marked with readonly.

Apply this diff:

 export default function ComponentSelectRandomHolders({
   onNextStep,
   onSelectRandomHolders,
   title,
   uniqueWalletsCount = null,
   isLoadingUniqueWalletsCount = false,
   onClose,
-}: {
+}: Readonly<{
   onNextStep: (step: PhaseConfigStep) => void;
   onSelectRandomHolders: (param: {
     value: number;
     randomHoldersType: RandomHoldersType;
     weightType: ComponentRandomHoldersWeightType;
     seed: string;
   }) => void;
   title: string;
   uniqueWalletsCount?: number | null;
   isLoadingUniqueWalletsCount?: boolean;
   onClose: () => void;
-}) {
+}>) {
♻️ Duplicate comments (1)
components/delegation/NewAssignPrimaryAddress.tsx (1)

117-121: Previous inconsistent comparison issue is resolved.

The validation now consistently uses areEqualAddresses helper which internally uses strict equality (===), addressing the previous review concern about mixed == and === usage.

🧹 Nitpick comments (12)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (1)

45-47: Remove redundant wrapper function.

The configure function simply calls onConfigureGroup() without any additional logic. Pass onConfigureGroup directly to the button's onClick handler.

Apply this diff:

-  const configure = () => {
-    onConfigureGroup();
-  };
-
   return (
     <div className="tw-p-6">
       <BuildPhaseFormConfigModalTitle title={title} onClose={onClose} />
       <DistributionPlanSecondaryText>
         Here you can see your snapshot configurations.
         <br />
         If you would like to add another snapshot, click &ldquo;Add another
         snapshot&rdquo;, otherwise click &ldquo;Configure Group&rdquo;.
       </DistributionPlanSecondaryText>
       {!!groupSnapshots.length && (
         <div className="tw-mt-6">
           <FinalizeSnapshotsTable
             onRemoveGroupSnapshot={onRemoveGroupSnapshot}
             groupSnapshots={groupSnapshots}
             snapshots={snapshots}
             phases={phases}
           />
         </div>
       )}
       <div className="tw-mt-8 tw-w-full tw-flex tw-items-center tw-justify-between">
         <ComponentConfigMeta
           tags={[]}
           walletsCount={uniqueWalletsCount}
           isLoading={isLoadingUniqueWalletsCount}
         />
         <div className="tw-gap-x-4 tw-flex tw-justify-end">
           <button
             onClick={onAddAnotherSnapshot}
             type="button"
             className="tw-inline-flex tw-items-center tw-justify-center tw-cursor-pointer tw-bg-transparent hover:tw-bg-neutral-800/80 tw-px-4 tw-py-3 tw-text-sm tw-font-medium tw-text-white tw-border-2 tw-border-solid tw-border-neutral-700 tw-rounded-lg tw-transition tw-duration-300 tw-ease-out">
             Add another snapshot
           </button>
           <button
-            onClick={configure}
+            onClick={onConfigureGroup}
             type="button"
             className="tw-relative tw-inline-flex tw-items-center tw-justify-center tw-cursor-pointer tw-bg-primary-500 tw-px-4 tw-py-3 tw-text-sm tw-font-medium tw-text-white tw-border tw-border-solid tw-border-primary-500 tw-rounded-lg hover:tw-bg-primary-600 hover:tw-border-primary-600 tw-transition tw-duration-300 tw-ease-out">
             Configure Group
           </button>
         </div>
       </div>
     </div>
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (3)

127-129: Consider removing deprecated wallet counting logic.

These constants are now hardcoded (loading = false, localUniqueWalletsCount = null) but still passed to child components. If the wallet counting feature is truly deprecated, consider either:

  • Removing these constants and updating the child component props
  • Adding a brief explanation of why they're retained for backward compatibility

This would improve code clarity and reduce confusion for future maintainers.


51-62: Prefer useMemo for derived options.

The options state and its effect (lines 51-62) duplicate the initial calculation (lines 38-49). Consider using useMemo to derive options directly from phases:

-  const [options, setOptions] = useState<
-    AllowlistToolSelectMenuMultipleOption[]
-  >([
-    SELECT_ALL_OPTION,
-    ...phases.flatMap((p) =>
-      p.components.map((c) => ({
-        title: c.name,
-        subTitle: p.name,
-        value: c.id,
-      }))
-    ),
-  ]);
-
-  useEffect(() => {
-    setOptions([
-      SELECT_ALL_OPTION,
-      ...phases.flatMap((p) =>
-        p.components.map((c) => ({
-          title: c.name,
-          subTitle: p.name,
-          value: c.id,
-        }))
-      ),
-    ]);
-  }, [phases]);
+  const options = useMemo<AllowlistToolSelectMenuMultipleOption[]>(
+    () => [
+      SELECT_ALL_OPTION,
+      ...phases.flatMap((p) =>
+        p.components.map((c) => ({
+          title: c.name,
+          subTitle: p.name,
+          value: c.id,
+        }))
+      ),
+    ],
+    [phases]
+  );

This eliminates redundant state and ensures options are always in sync with phases.


102-112: Derive excludeComponentWinners directly from selectedOptions.

The excludeComponentWinners state and effect (lines 102-112) can be replaced with a derived value:

-  const [excludeComponentWinners, setExcludeComponentWinners] = useState<
-    string[]
-  >([]);
-
-  useEffect(() => {
-    setExcludeComponentWinners(
-      selectedOptions
-        .filter((o) => o.value !== SELECT_ALL_OPTION.value)
-        .map((o) => o.value)
-    );
-  }, [selectedOptions]);
+  const excludeComponentWinners = useMemo(
+    () =>
+      selectedOptions
+        .filter((o) => o.value !== SELECT_ALL_OPTION.value)
+        .map((o) => o.value),
+    [selectedOptions]
+  );

This removes unnecessary state and guarantees consistency between the two values.

components/community-downloads/CommunityDownloadsComponent.tsx (1)

25-25: Consider moving URL construction into queryFn or using useMemo.

The fullUrl constant is recreated on every render. While string concatenation is inexpensive, for cleaner code you could either move it inside the queryFn or wrap it in useMemo.

Option 1 (preferred): Move into queryFn:

- const fullUrl = `${props.url}?page_size=${PAGE_SIZE}&page=${page}`;
-
  const { data, isError } = useQuery<ApiUploadsPage>({
    queryKey: ["community-downloads", props.url, page],
-   queryFn: () => fetchUrl(fullUrl),
+   queryFn: () => fetchUrl(`${props.url}?page_size=${PAGE_SIZE}&page=${page}`),
    placeholderData: keepPreviousData,
  });

Option 2: Use useMemo:

+ const fullUrl = useMemo(
+   () => `${props.url}?page_size=${PAGE_SIZE}&page=${page}`,
+   [props.url, page]
+ );
+
  const { data, isError } = useQuery<ApiUploadsPage>({
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (1)

36-42: Simplify redundant type check.

The type guard typeof maxMints === "number" is redundant here because the previous check (line 28) with early return guarantees that if execution reaches line 36, maxMints is already a number.

Apply this diff to simplify:

-    if (typeof maxMints === "number" && maxMints < 1) {
+    if (maxMints < 1) {
       setToasts({
         messages: ["Max mint count must be greater than 0."],
         type: "error",
       });
       return;
     }
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

53-53: Remove unnecessary variable assignment.

The poolTypeToString variable simply aliases the POOL_TYPE_TO_STRING constant without adding value. Consider using POOL_TYPE_TO_STRING directly throughout the component (lines 59, 90) to reduce indirection.

Apply this diff:

-  const poolTypeToString = POOL_TYPE_TO_STRING;
-
   const options: AllowlistToolSelectMenuMultipleOption[] = snapshots
     .filter((s) => s.id !== config.snapshotId)
     .map((s) => ({
       title: s.name,
-      subTitle: poolTypeToString[s.poolType],
+      subTitle: POOL_TYPE_TO_STRING[s.poolType],
       value: s.id,
     }));

And update line 90:

-    const poolStringToPoolType = (str: string): Pool => {
-      const poolType = Object.entries(poolTypeToString)
+    const poolStringToPoolType = (str: string): Pool => {
+      const poolType = Object.entries(POOL_TYPE_TO_STRING)
components/distribution-plan-tool/create-plan/CreatePlan.tsx (3)

26-30: Remove unnecessary async/await.

The setState function is typically synchronous in React contexts. The async/await here is unnecessary and potentially misleading.

-  const applyDistributionPlan = useEffectEvent(
-    async (distributionPlan: AllowlistDescription) => {
-      await setState(distributionPlan);
-    }
-  );
+  const applyDistributionPlan = useEffectEvent(
+    (distributionPlan: AllowlistDescription) => {
+      setState(distributionPlan);
+    }
+  );

33-36: Replace alert() with toast notification.

Using alert() provides poor UX. Use a toast notification for consistency with the rest of the application (e.g., makeErrorToast).

     if (!id) {
-      alert("No id found");
+      makeErrorToast("No id found");
       redirectToEmma();
       return;
     }

Note: You'll need to import makeErrorToast from the appropriate location.


39-66: Good cleanup pattern with minor inconsistency.

The isActive flag correctly prevents state updates after unmount. However, the error path at line 50 calls redirectToEmma() without checking isActive, while the catch block at line 56-58 does check it. For consistency, consider checking isActive before all navigation calls.

         if (!response.success || !response.data) {
+          if (!isActive) return;
           redirectToEmma();
           return;
         }
components/brain/direct-messages/DirectMessagesList.tsx (1)

126-126: Consider memoizing the waves transformation.

The .map() creates a new array on every render. For better performance, consider memoizing this transformation:

+  const wavesWithPinned = useMemo(
+    () => list.map((w) => ({ ...w, isPinned: false })),
+    [list]
+  );
+
   return (
     <div className="tw-mb-4">
       ...
         <UnifiedWavesListWaves
           ref={listRef}
-          waves={list.map((w) => ({ ...w, isPinned: false }))}
+          waves={wavesWithPinned}

Add the import:

-import React, { useRef, useEffect, useContext, useEffectEvent } from "react";
+import React, { useRef, useEffect, useContext, useEffectEvent, useMemo } from "react";
components/delegation/walletChecker/WalletChecker.tsx (1)

277-293: refetchConsolidatedWallets should be wrapped in useCallback.

The refetch function from useQuery is stable, but wrapping it in useCallback would make the dependency more explicit and prevent potential future issues if the query hook implementation changes.

Apply this diff:

-  const { refetch: refetchConsolidatedWallets } = useQuery({
+  const { refetch: refetchConsolidatedWalletsRaw } = useQuery({
     queryKey: ["consolidated-wallets", fetchedAddress],
     queryFn: async () => {
       // ... queryFn implementation
     },
     enabled: false,
     refetchOnWindowFocus: false,
     onSuccess: (mappedWallets) => {
       setConsolidatedWallets(mappedWallets);
     },
     onError: () => {
       setConsolidatedWallets([]);
     },
   });
+
+  const refetchConsolidatedWallets = useCallback(() => {
+    void refetchConsolidatedWalletsRaw();
+  }, [refetchConsolidatedWalletsRaw]);

   useEffect(() => {
     if (!consolidationsLoaded || !fetchedAddress) {
       return;
     }

     if (!consolidations.length) {
       setConsolidatedWallets([]);
       return;
     }

     void refetchConsolidatedWallets();
   }, [
     consolidationsLoaded,
     consolidations,
     fetchedAddress,
     refetchConsolidatedWallets,
   ]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 712e3a8 and 3b54e9a.

📒 Files selected for processing (26)
  • __tests__/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx (0 hunks)
  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (3 hunks)
  • components/brain/direct-messages/DirectMessagesList.tsx (4 hunks)
  • components/brain/left-sidebar/waves/BrainLeftSidebarWaves.tsx (0 hunks)
  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx (4 hunks)
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx (1 hunks)
  • components/brain/my-stream/MyStreamWaveDesktopTabs.tsx (3 hunks)
  • components/brain/my-stream/MyStreamWaveFAQ.tsx (1 hunks)
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (4 hunks)
  • components/community-downloads/CommunityDownloadsComponent.tsx (3 hunks)
  • components/delegation/CollectionDelegation.tsx (15 hunks)
  • components/delegation/DelegationFormParts.tsx (10 hunks)
  • components/delegation/NewAssignPrimaryAddress.tsx (6 hunks)
  • components/delegation/UpdateDelegation.tsx (3 hunks)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (5 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx (2 hunks)
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx (2 hunks)
  • hooks/useEnsResolution.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • tests/components/brain/left-sidebar/waves/UnifiedWavesList.test.tsx
  • components/brain/left-sidebar/waves/BrainLeftSidebarWaves.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsx
  • components/brain/my-stream/MyStreamWaveDesktopTabs.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsx
  • components/brain/left-sidebar/waves/UnifiedWavesList.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
  • components/brain/my-stream/MyStreamWaveFAQ.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx
  • components/delegation/UpdateDelegation.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx
  • hooks/useEnsResolution.ts
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/delegation/CollectionDelegation.tsx
  • components/delegation/NewAssignPrimaryAddress.tsx
  • components/delegation/DelegationFormParts.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx
  • components/delegation/UpdateDelegation.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/delegation/CollectionDelegation.tsx
  • components/delegation/NewAssignPrimaryAddress.tsx
  • components/delegation/DelegationFormParts.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.tsx : Use FontAwesome for icons

Applied to files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/community-downloads/CommunityDownloadsComponent.tsx
📚 Learning: 2025-09-28T12:33:56.329Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:56.329Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call fetch directly with user-controlled or scraped URLs in API code; use @/lib/security/urlGuard helpers (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) so every hop is validated

Applied to files:

  • components/community-downloads/CommunityDownloadsComponent.tsx
🧬 Code graph analysis (10)
components/distribution-plan-tool/create-plan/CreatePlan.tsx (2)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistDescription (12-18)
services/distribution-plan-api.ts (1)
  • distributionPlanApiFetch (38-62)
components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (1)
generated/models/ApiDrop.ts (1)
  • ApiDrop (28-227)
components/delegation/UpdateDelegation.tsx (1)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
components/community-downloads/CommunityDownloadsComponent.tsx (4)
components/leaderboard/NFTLeaderboard.tsx (1)
  • PAGE_SIZE (27-27)
generated/models/ApiUploadsPage.ts (1)
  • ApiUploadsPage (16-56)
services/6529api.ts (1)
  • fetchUrl (6-19)
components/community-downloads/CommunityDownloadsHelpers.tsx (1)
  • DownloadsLayout (23-48)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
components/delegation/CollectionDelegation.tsx (1)
components/delegation/delegation-constants.ts (1)
  • CONSOLIDATION_USE_CASE (79-83)
components/delegation/NewAssignPrimaryAddress.tsx (3)
components/auth/Auth.tsx (1)
  • AuthContext (83-93)
helpers/Helpers.ts (1)
  • areEqualAddresses (149-154)
components/delegation/DelegationFormParts.tsx (4)
  • DelegationFormOriginalDelegatorFormGroup (80-109)
  • DelegationFormLabel (49-78)
  • DelegationAddressDisabledInput (111-122)
  • DelegationCloseButton (440-468)
components/delegation/DelegationFormParts.tsx (2)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
helpers/AllowlistToolHelpers.ts (1)
  • getRandomObjectId (46-48)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (2)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
⏰ 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 (31)
components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (3)

4-5: LGTM: FontAwesome imports added correctly.

The imports align with the coding guidelines requiring FontAwesome for icons.


40-40: LGTM: Simplified hook usage.

Correctly ignores the unused copyState from the hook since the component manages its own coping state for UI feedback.


51-55: LGTM: FontAwesome icon implementation is correct.

The replacement of inline SVG with FontAwesomeIcon aligns with the coding guidelines and is properly implemented with correct styling and event handling.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (1)

22-23: LGTM: Optional props with sensible defaults.

The default values (null for uniqueWalletsCount and false for isLoadingUniqueWalletsCount) are appropriate and align with their usage in the component.

Also applies to: 34-35

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)

27-28: LGTM! Props now follow coding guidelines.

Good addition of readonly modifiers to the props interface, which aligns with the coding guidelines.

components/community-downloads/CommunityDownloadsComponent.tsx (2)

27-31: Excellent migration to react-query!

This implementation successfully addresses the critical issue from the previous review. The use of useQuery with proper queryKey, error handling via isError, and keepPreviousData for smooth transitions follows best practices and resolves the concerns about race conditions, memory leaks, and error handling.


36-39: Good use of useCallback for pagination handler.

The handlePageChange callback properly memoizes the page change logic with scroll-to-top behavior. The empty dependency array is correct since setPage is stable.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (1)

13-14: LGTM! Optional props with sensible defaults.

Making uniqueWalletsCount and isLoadingUniqueWalletsCount optional with appropriate default values (null and false) improves component flexibility without breaking existing behavior. This aligns well with the broader refactoring effort mentioned in the PR summary.

Also applies to: 19-20

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (5)

79-82: Proper state initialization restores functionality.

The state initialization now correctly starts from config.uniqueWalletsCount (line 81) and includes a loading state (line 82), addressing the previous concerns about hardcoded null and disabled loading feedback. This properly restores the unique wallets count functionality.


128-130: LGTM!

The type assertion for CustomTokenPoolParamsToken correctly matches the interface definition and safely extracts the owner property from custom token pool tokens.


141-141: LGTM!

The dependency array correctly removes poolTypeToString since it's now a constant, and includes all necessary reactive dependencies.


145-227: Well-structured effect with proper cleanup and error handling.

The implementation demonstrates good practices:

  • isActive flag prevents race conditions and stale state updates
  • Early returns with proper cleanup when essential data is missing (lines 156-168)
  • getCustomTokenPoolWallets uses proper type guards and deduplication (lines 170-188)
  • Loading state is correctly managed in fetchUniqueWalletsCount
  • Success validation checks both success flag and data type (line 211)

The react-query violation was flagged separately.


228-235: LGTM!

The dependency array correctly includes all reactive values used within the effect. State setters are correctly omitted as they're stable by design.

components/distribution-plan-tool/create-plan/CreatePlan.tsx (2)

22-24: Good use of useEffectEvent for navigation.

This pattern correctly wraps the navigation logic in a stable event handler.


3-3: ✓ React version verified: 19.2.0 supports useEffectEvent.

The project uses React 19.2.0, which meets the minimum requirement for useEffectEvent. The import is valid.

components/brain/direct-messages/DirectMessagesList.tsx (5)

3-3: LGTM - useEffectEvent is stable in React 19.2.

The import of useEffectEvent is correct. Ensure the project is using React 19.2+ as this hook was stabilized in that version.


33-39: LGTM - Clean destructuring refactor.

Extracting these fields from directMessages improves code readability throughout the component.


42-53: LGTM - Correct useEffectEvent usage.

The reset effect and fetchNextPageIfNeeded implementation using useEffectEvent is correct. This pattern creates a stable callback that accesses the latest values without needing to be in dependency arrays, preventing duplicate fetches while maintaining correct state access.


55-75: LGTM - IntersectionObserver correctly integrated with useEffectEvent.

The observer setup is correct. The dependencies include pagination state changes that trigger observer recreation. Note that fetchNextPageIfNeeded (created with useEffectEvent) is intentionally not in the dependency array per React 19 patterns.


135-136: Past review comment addressed.

The missing isFetching prop has been correctly added with an appropriate condition to show loading state when the list is empty.

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

26-26: LGTM: Derived isEditing is more efficient.

Computing isEditing directly from voteValue !== currentVoteValue eliminates unnecessary state and effect overhead.

hooks/useEnsResolution.ts (2)

13-97: LGTM: Well-designed ENS resolution hook.

The hook cleanly centralizes ENS resolution logic with proper memoization and state synchronization. The pendingAddress pattern in the ENS name effect correctly avoids stale closures.


99-124: I need to understand the function's intended behavior and how it's used in the codebase.

The current implementation handles multiple separators correctly and does not require changes.

The test execution confirms that normalizeInputWithResolvedAddress handles multiple consecutive labels predictably and consistently:

  • When the last part is an address (starts with 0x), it replaces it with the resolved address
  • When the last part is not an address, it appends the resolved address

This is the intended design, not a bug. The function processes inputs with multiple separators by targeting only the last segment, which is appropriate for normalizing ENS name chains where addresses may appear at the end.

components/delegation/UpdateDelegation.tsx (1)

54-58: LGTM: Clean migration to useEnsResolution hook.

The refactor successfully replaces direct ENS state management with the centralized hook, simplifying the component logic.

components/delegation/NewAssignPrimaryAddress.tsx (1)

45-53: LGTM: Clean destructuring pattern.

Local destructuring improves readability and reduces prop drilling throughout the component.

components/delegation/DelegationFormParts.tsx (2)

24-46: LGTM: Simplified ENS resolution with the new hook.

DelegationAddressInput now leverages useEnsResolution, eliminating manual state synchronization and reducing complexity.


249-258: LGTM: Destructuring improves clarity.

Local destructuring makes the function body more readable and reduces repetitive props. prefixes.

components/delegation/walletChecker/WalletChecker.tsx (3)

92-123: LGTM: Clean migration to react-query.

The delegations query properly uses enabled flag and separates regular delegations from sub-delegations in the success handler.


125-171: LGTM: Consolidation normalization handles reciprocals correctly.

The setAllConsolidations callback correctly creates reciprocal entries for confirmed consolidations and deduplicates entries.


230-275: LGTM: Efficient memoization of derived state.

Both activeDelegation and consolidationActions use useMemo appropriately to avoid recalculating on every render.

components/delegation/CollectionDelegation.tsx (1)

3-3: No issues found—React 19 is confirmed.

The project is already on React 19.2.0, which fully supports useEffectEvent. The import is valid and poses no build risk.

Comment thread components/brain/direct-messages/DirectMessagesList.tsx Outdated
Comment thread components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
Comment thread components/distribution-plan-tool/create-plan/CreatePlan.tsx Outdated
Signed-off-by: Simo <simo@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

39-48: Add missing readonly modifiers to props.

The inline props type definition is missing readonly modifiers, which violates the coding guidelines requirement: "Always add readonly before props".

Apply this diff to add the required modifiers:

 }: {
-  snapshots: DistributionPlanSnapshot[];
-  config: PhaseGroupSnapshotConfig;
-  onSkip: () => void;
-  onSelectExcludeOtherSnapshots: (param: {
+  readonly snapshots: DistributionPlanSnapshot[];
+  readonly config: PhaseGroupSnapshotConfig;
+  readonly onSkip: () => void;
+  readonly onSelectExcludeOtherSnapshots: (param: {
     snapshotsToExclude: PhaseGroupSnapshotConfigExcludeSnapshot[];
     uniqueWalletsCount: number | null;
   }) => void;
-  title: string;
-  onClose: () => void;
+  readonly title: string;
+  readonly onClose: () => void;
 }) {

As per coding guidelines.

🧹 Nitpick comments (2)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)

167-168: Hardcoded null/false values may degrade user experience.

Setting walletsCount={null} and isLoading={false} means the component will never display wallet count information or loading states, even though config.uniqueWalletsCount is available and could be used.

Consider passing config.uniqueWalletsCount instead of null:

         <ComponentConfigMeta
           tags={[]}
-          walletsCount={null}
-          isLoading={false}
+          walletsCount={config.uniqueWalletsCount}
+          isLoading={false}
         />
components/brain/direct-messages/DirectMessagesList.tsx (1)

59-79: Consider including sentinel in the effect dependencies.

The effect reads sentinel and containerRef from listRef.current but doesn't include them in the dependency array. If sentinel doesn't exist on the first effect run and the dependencies [hasNextPage, isFetchingNextPage] don't change, the observer won't be set up even when sentinel becomes available later.

While this pattern usually works because refs are stable and the dependencies typically change after data fetching, it could cause the observer to not initialize if timing is off.

Consider one of these approaches:

Option 1: Add a dependency that ensures re-run when sentinel is ready:

-  }, [hasNextPage, isFetchingNextPage]);
+  }, [hasNextPage, isFetchingNextPage, list.length > 0]);

Option 2: Remove the early-return conditions from the effect and handle them in the observer callback, allowing the observer to be set up once:

   useEffect(() => {
     const listHandle = listRef.current;
     const sentinel = listHandle?.sentinelRef.current;

-    if (!sentinel || !hasNextPage || isFetchingNextPage) {
+    if (!sentinel) {
       return;
     }

     const observer = new IntersectionObserver(([entry]) => {
-      if (entry.isIntersecting) {
+      if (entry.isIntersecting && hasNextPage && !isFetchingNextPage) {
         fetchNextPageIfNeeded();
       }
     }, {
       root: listHandle?.containerRef.current,
       rootMargin: "100px",
     });

     observer.observe(sentinel);

     return () => observer.disconnect();
-  }, [hasNextPage, isFetchingNextPage]);
+  }, []);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b54e9a and 16bd8a1.

📒 Files selected for processing (18)
  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx (3 hunks)
  • components/brain/direct-messages/DirectMessagesList.tsx (4 hunks)
  • components/brain/left-sidebar/waves/BrainLeftSidebarWaves.tsx (1 hunks)
  • components/brain/left-sidebar/web/WebBrainLeftSidebarWaves.tsx (0 hunks)
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx (1 hunks)
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx (6 hunks)
  • components/community-downloads/CommunityDownloadsComponent.tsx (3 hunks)
  • components/delegation/UpdateDelegation.tsx (3 hunks)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7 hunks)
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx (2 hunks)
  • eslint.config.mjs (2 hunks)
  • hooks/useEnsResolution.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • components/brain/left-sidebar/web/WebBrainLeftSidebarWaves.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • components/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsx
  • components/brain/left-sidebar/waves/BrainLeftSidebarWaves.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/delegation/UpdateDelegation.tsx
  • hooks/useEnsResolution.ts
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/brain/left-sidebar/web/WebUnifiedWavesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/delegation/UpdateDelegation.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
__tests__/**

📄 CodeRabbit inference engine (tests/AGENTS.md)

Place Jest test suites under the __tests__ directory mirroring source folders (e.g., components, contexts, hooks, utils)

Files:

  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
__tests__/components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (tests/AGENTS.md)

Use @testing-library/react and @testing-library/user-event for React component tests

Files:

  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
🧠 Learnings (8)
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/create-plan/CreatePlan.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Always add readonly before props

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
📚 Learning: 2025-09-28T12:33:56.329Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:56.329Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call fetch directly with user-controlled or scraped URLs in API code; use @/lib/security/urlGuard helpers (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) so every hop is validated

Applied to files:

  • components/community-downloads/CommunityDownloadsComponent.tsx
📚 Learning: 2025-09-28T12:33:30.950Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:30.950Z
Learning: Applies to __tests__/components/**/*.{ts,tsx,js,jsx} : Use `testing-library/react` and `testing-library/user-event` for React component tests

Applied to files:

  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
  • eslint.config.mjs
📚 Learning: 2025-09-28T12:33:07.561Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __mocks__/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:07.561Z
Learning: Applies to __mocks__/**/__mocks__/**/*.{js,jsx,ts,tsx} : Mock only external dependencies or heavy functionality; avoid over-mocking internal logic

Applied to files:

  • __tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Do not include any comments in the code

Applied to files:

  • components/brain/direct-messages/DirectMessagesList.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version

Applied to files:

  • eslint.config.mjs
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.tsx : Use TailwindCSS for styling

Applied to files:

  • eslint.config.mjs
🧬 Code graph analysis (8)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (3)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (1)
  • PhaseGroupSnapshotConfigExcludeSnapshot (62-66)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/distribution-plan-tool/create-plan/CreatePlan.tsx (4)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
services/distribution-plan-api.ts (1)
  • distributionPlanApiFetch (38-62)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistDescription (12-18)
services/distribution-plan.utils.ts (1)
  • makeErrorToast (2-12)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (2)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (2)
  • PhaseGroupSnapshotConfig (68-83)
  • DistributionPlanSnapshot (55-60)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
components/community-downloads/CommunityDownloadsComponent.tsx (3)
generated/models/ApiUploadsPage.ts (1)
  • ApiUploadsPage (16-56)
services/6529api.ts (1)
  • fetchUrl (6-19)
components/community-downloads/CommunityDownloadsHelpers.tsx (1)
  • DownloadsLayout (23-48)
__tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx (3)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (1)
  • PhaseGroupSnapshotConfig (68-83)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)
  • SnapshotExcludeComponentWinners (36-173)
components/delegation/UpdateDelegation.tsx (1)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (4)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (1)
  • PhaseGroupSnapshotConfig (68-83)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
⏰ 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 (29)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx (1)

25-26: LGTM! Props correctly updated to optional with appropriate defaults.

The changes properly implement the optional prop pattern with sensible defaults (null for uniqueWalletsCount, false for isLoadingUniqueWalletsCount) and add the required Readonly<> wrapper per coding guidelines. The component logic correctly handles these default values throughout (lines 86, 178-199, 281).

Also applies to: 28-28, 37-40

eslint.config.mjs (5)

9-22: Excellent defensive error handling for optional dependency.

The dynamic import pattern with MODULE_NOT_FOUND handling is well-implemented. The defensive checks for error type (lines 14-16) before accessing properties prevent potential runtime issues, and selective rethrowing ensures real errors aren't silently swallowed.


27-31: Good refactor: centralized plugin configuration.

Extracting plugins into a dedicated object improves maintainability and enables the conditional addition pattern used for the optional React Compiler plugin.


33-56: LGTM: centralized rule configuration.

Consolidating rules into a single object improves readability and pairs well with the conditional addition pattern for optional plugins.


58-61: Conditional plugin activation works correctly.

The logic cleanly adds the plugin and rule only when available, making the React Compiler plugin truly optional without affecting the rest of the linting configuration.


78-80: Clean integration of refactored configuration.

The centralized plugins and rules objects integrate cleanly into the ESLint config, maintaining existing behavior while enabling optional dependency handling.

components/brain/left-sidebar/web/WebUnifiedWavesList.tsx (1)

23-33: LGTM! Clean refactor to internal destructuring.

The change from destructuring in the function signature to accepting a props object with internal destructuring is valid and maintains all existing functionality. The pattern is consistent, type-safe, and preserves the default value for isCollapsed.

components/community-downloads/CommunityDownloadsComponent.tsx (6)

3-4: LGTM! Imports support the react-query migration.

The addition of useCallback and react-query imports (useQuery, keepPreviousData) properly supports the refactored data-fetching pattern that addresses previous review feedback.


19-20: LGTM! Props correctly use readonly modifier.

The Props interface properly uses readonly for both fields, following the coding guidelines for TypeScript files.


33-34: LGTM! Correctly derives state from query data.

The component properly extracts downloads and totalResults from the query data using optional chaining and sensible defaults.


36-39: LGTM! Well-optimized page change handler.

The useCallback hook properly memoizes the page change handler with the correct (empty) dependency array, and the scroll-to-top behavior enhances UX during pagination.


43-47: LGTM! Good error handling with user-friendly message.

The error state is properly handled with a clear, user-friendly message styled with TailwindCSS as per the coding guidelines.


23-76: Excellent migration to react-query!

This refactor successfully addresses the previous review feedback by migrating from manual useEffect-based fetching to react-query's useQuery. The implementation eliminates race conditions, memory leaks, and unhandled promise rejections that were concerns with the previous approach. The component now benefits from automatic request cancellation, caching, and error handling provided by react-query.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (2)

17-21: LGTM! Props now comply with coding guidelines.

The readonly modifiers have been correctly added to all props as required by the coding guidelines.


46-46: Good refactor: derived validation replaces useEffect.

Replacing the useEffect-based validation with a derived isDisabled value is cleaner and follows React best practices by eliminating unnecessary side effects.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (2)

45-57: Good use of memoization for performance.

Memoizing the options array prevents unnecessary re-computation and downstream re-renders when the component updates for other reasons.


63-83: Synchronization logic handles the scenario without crashing, but silently drops stale component IDs.

The useEffect correctly handles when options changes due to phases being updated: when a component is deleted from phases, line 73-75 filters selectedOptions to only include IDs that still exist in the current options array. Stale IDs in config.excludeComponentWinners are silently excluded from selectedOptions without user notification.

However, this behavior warrants verification:

  • No warning when data is lost: if a previously selected component is deleted from phases, the user won't know it was dropped from their selection
  • No test coverage: the test file covers basic selection but not this edge case scenario
  • Business intent unclear: confirm whether silent removal is acceptable or if validation/warning is needed before form submission
__tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsx (2)

41-51: Good test setup with properly typed baseConfig.

The baseConfig constant provides a clean, DRY foundation for test cases and is correctly typed as PhaseGroupSnapshotConfig.


64-76: Test correctly validates new config-based API.

The test properly creates a config variant with uniqueWalletsCount: 42 and verifies it's passed through correctly in the callback, which aligns with the component's new behavior of using config.uniqueWalletsCount.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (4)

26-30: Good refactor: constant replaces dynamic state.

Extracting POOL_TYPE_TO_STRING as a constant mapping eliminates unnecessary state management and improves maintainability.


142-162: Well-implemented memoization for extra wallets extraction.

The memoized currentSnapshotExtraWallets correctly handles custom token pool owner extraction with proper type safety using CustomTokenPoolParamsToken, deduplication, and case normalization.


164-204: Excellent migration to react-query!

The component now uses useQuery for data fetching per coding guidelines, which addresses previous review concerns. The implementation includes:

  • Proper query key with all dependencies
  • Robust error handling and data validation
  • Conditional enabling based on shouldFetchUniqueWalletsCount

This is a significant improvement over the previous hardcoded approach.

As per coding guidelines.


206-222: State synchronization effects handle all scenarios correctly.

The three useEffect hooks properly manage localUniqueWalletsCount by:

  1. Resetting to config.uniqueWalletsCount when not fetching
  2. Updating with fetched data when available
  3. Falling back to config on error

This ensures consistent state across different fetch scenarios.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (3)

14-26: Good refactor: dedicated props interface improves type safety.

Introducing FinalizeSnapshotProps with readonly modifiers on all props improves maintainability and complies with coding guidelines.

As per coding guidelines.


36-37: Appropriate default values for optional props.

Setting defaults of null for uniqueWalletsCount and false for isLoadingUniqueWalletsCount provides sensible fallback behavior when these values aren't provided.


80-80: Simplified onClick handler improves readability.

Directly calling onConfigureGroup instead of wrapping it in a helper function is cleaner and more straightforward.

components/brain/direct-messages/DirectMessagesList.tsx (3)

82-85: LGTM!

Proper use of useMemo to avoid recreating the annotated array on every render. The dependency on list ensures the memoized value updates when the list changes.


38-44: LGTM!

The destructuring improves readability, and the props are correctly threaded through to child components. The conditional isFetching && list.length === 0 on line 143 properly shows the initial loading state only when the list is empty.

Also applies to: 134-134, 143-150


7-7: React 19.2.0 fully supports useEffectEvent—verification passed.

The project uses React 19.2.0, which natively supports useEffectEvent. The implementation at lines 50–57 correctly uses this hook to create a stable callback for pagination, preventing redundant fetch calls. The code complies with all coding guidelines: no inline comments, readonly props, proper hook usage, and correct memoization of wavesWithPinned. No issues found.

Comment thread components/community-downloads/CommunityDownloadsComponent.tsx Outdated
Comment thread components/delegation/walletChecker/WalletChecker.tsx Outdated
Comment thread components/delegation/walletChecker/WalletChecker.tsx
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/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

206-222: Consider consolidating state synchronization logic.

The three separate effects managing localUniqueWalletsCount are correct but could be simplified. Consider combining them into a single effect or deriving the value directly from the query state to reduce complexity.

For example, you could consolidate into a single effect:

-  useEffect(() => {
-    if (!shouldFetchUniqueWalletsCount) {
-      setLocalUniqueWalletsCount(config.uniqueWalletsCount);
-    }
-  }, [shouldFetchUniqueWalletsCount, config.uniqueWalletsCount]);
-
-  useEffect(() => {
-    if (typeof fetchedUniqueWalletsCount === "number") {
-      setLocalUniqueWalletsCount(fetchedUniqueWalletsCount);
-    }
-  }, [fetchedUniqueWalletsCount]);
-
-  useEffect(() => {
-    if (isUniqueWalletsCountError) {
-      setLocalUniqueWalletsCount(config.uniqueWalletsCount);
-    }
-  }, [isUniqueWalletsCountError, config.uniqueWalletsCount]);
+  useEffect(() => {
+    if (!shouldFetchUniqueWalletsCount || isUniqueWalletsCountError) {
+      setLocalUniqueWalletsCount(config.uniqueWalletsCount);
+    } else if (typeof fetchedUniqueWalletsCount === "number") {
+      setLocalUniqueWalletsCount(fetchedUniqueWalletsCount);
+    }
+  }, [
+    shouldFetchUniqueWalletsCount,
+    isUniqueWalletsCountError,
+    fetchedUniqueWalletsCount,
+    config.uniqueWalletsCount,
+  ]);
components/delegation/walletChecker/WalletChecker.tsx (1)

181-204: Consider graceful degradation for the second fetch.

The two-step consolidation fetch is logical, but if the second fetchUrl call fails, the entire query fails and users lose the firstData results. Consider wrapping the second fetch in a try-catch to return partial data on failure.

Example:

     queryFn: async () => {
       const baseUrl = `${publicEnv.API_ENDPOINT}/api/consolidations/${walletAddress}?show_incomplete=true`;
       const firstResponse = (await fetchUrl(baseUrl)) as DBResponse;
       const firstData = firstResponse.data as WalletConsolidation[];
 
       if (firstData.length > 0) {
         const newWallet = areEqualAddresses(walletAddress, firstData[0].wallet1)
           ? firstData[0].wallet2
           : firstData[0].wallet1;
         const nextUrl = `${publicEnv.API_ENDPOINT}/api/consolidations/${newWallet}?show_incomplete=true`;
-        const secondResponse = (await fetchUrl(nextUrl)) as DBResponse;
-        return [...firstData, ...(secondResponse.data as WalletConsolidation[])];
+        try {
+          const secondResponse = (await fetchUrl(nextUrl)) as DBResponse;
+          return [...firstData, ...(secondResponse.data as WalletConsolidation[])];
+        } catch {
+          return firstData;
+        }
       }
 
       return firstData;
     },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 16bd8a1 and aa855d4.

📒 Files selected for processing (6)
  • components/brain/direct-messages/DirectMessagesList.tsx (4 hunks)
  • components/brain/left-sidebar/web/WebBrainLeftSidebarWaves.tsx (1 hunks)
  • components/community-downloads/CommunityDownloadsComponent.tsx (3 hunks)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/brain/left-sidebar/web/WebBrainLeftSidebarWaves.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
  • components/brain/direct-messages/DirectMessagesList.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Always add readonly before props

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Do not include any comments in the code

Applied to files:

  • components/brain/direct-messages/DirectMessagesList.tsx
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/community-downloads/CommunityDownloadsComponent.tsx
📚 Learning: 2025-09-28T12:33:56.329Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: app/api/AGENTS.md:0-0
Timestamp: 2025-09-28T12:33:56.329Z
Learning: Applies to app/api/**/*.{ts,tsx,js,jsx} : Never call fetch directly with user-controlled or scraped URLs in API code; use @/lib/security/urlGuard helpers (parsePublicUrl, assertPublicUrl, fetchPublicUrl, fetchPublicJson) so every hop is validated

Applied to files:

  • components/community-downloads/CommunityDownloadsComponent.tsx
🧬 Code graph analysis (4)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (4)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (1)
  • PhaseGroupSnapshotConfig (68-83)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (5)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
  • DistributionPlanSnapshot (55-60)
  • PhaseGroupSnapshotConfig (68-83)
  • PhaseGroupSnapshotConfigExcludeSnapshot (62-66)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/community-downloads/CommunityDownloadsComponent.tsx (3)
generated/models/ApiUploadsPage.ts (1)
  • ApiUploadsPage (16-56)
services/6529api.ts (1)
  • fetchUrl (6-19)
components/community-downloads/CommunityDownloadsHelpers.tsx (1)
  • DownloadsLayout (23-48)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
⏰ 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 (27)
components/community-downloads/CommunityDownloadsComponent.tsx (1)

3-80: Excellent implementation - all previous feedback addressed!

The react-query migration is well-executed and addresses all concerns from previous reviews:

  • ✅ Proper query key with all dependencies (props.url, page)
  • ✅ Automatic error handling with user-friendly error message
  • ✅ Loading state properly displayed during initial fetch
  • ✅ Race conditions eliminated via react-query's automatic cancellation
  • ✅ Memory leaks prevented by react-query's cleanup
  • placeholderData: keepPreviousData provides smooth pagination UX
  • handlePageChange properly memoized with useCallback
  • readonly modifiers on props per coding guidelines
  • ✅ Clean derived state without manual synchronization

The loading check isLoading && !data is particularly well-thought-out: it shows the loading indicator only on initial fetch, while subsequent page changes show stale data from placeholderData for better UX.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (5)

3-3: LGTM: useMemo import added for memoization.

The addition of useMemo to the React imports is appropriate for the memoization improvements implemented in this component.


45-57: LGTM: Proper memoization of options.

The options are correctly memoized with phases as the dependency, which will prevent unnecessary recalculations when other state changes.


119-125: LGTM: Proper memoization of excludeComponentWinners.

The derived excludeComponentWinners array is correctly memoized based on selectedOptions, improving performance by avoiding redundant filtering operations.


63-83: LGTM: Robust synchronization logic.

The effect correctly synchronizes the config.excludeComponentWinners with selectedOptions, handling empty selections, partial selections, and the "select all" scenario appropriately.


127-139: LGTM: Proper validation and callback logic.

The validation ensures at least one component is selected before proceeding, and the callback correctly uses the memoized excludeComponentWinners and config.uniqueWalletsCount.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7)

26-30: LGTM: Centralized pool type mapping.

The POOL_TYPE_TO_STRING constant provides a centralized mapping for pool types, improving maintainability. Including WALLET_POOL provides defensive coverage for potential future use.


3-3: LGTM: Appropriate imports for react-query implementation.

The addition of useMemo, CustomTokenPoolParamsToken, distributionPlanApiPost, and useQuery imports support the proper implementation of data fetching using react-query per coding guidelines.

Also applies to: 17-17, 23-24


40-48: LGTM: Readonly props comply with guidelines.

All props are correctly marked as readonly, adhering to the coding guideline requirement.


86-139: LGTM: Comprehensive snapshot exclusion logic.

The effect correctly computes snapshotsToExclude with proper handling for different pool types. The token owner extraction for CUSTOM_TOKEN_POOL correctly accesses the owner property from CustomTokenPoolParamsToken, and error handling is appropriate.


142-162: LGTM: Proper memoization of current snapshot owners.

The currentSnapshotExtraWallets memo correctly extracts and normalizes owner addresses from the current snapshot's tokens, with appropriate type guards and deduplication.


164-204: LGTM: Proper react-query implementation.

The useQuery implementation correctly follows coding guidelines by using react-query for data fetching. The query key is comprehensive, the enabled flag appropriately gates execution, and error handling is robust.


224-229: LGTM: Proper state usage in callbacks and UI.

The callback and component correctly use localUniqueWalletsCount and isUniqueWalletsCountLoading to provide appropriate functionality and user feedback.

Also applies to: 254-258

components/brain/direct-messages/DirectMessagesList.tsx (8)

3-9: LGTM!

The new imports (useEffectEvent and useMemo) are appropriate for the sentinel-based pagination refactor and memoization pattern introduced in this file.


24-26: LGTM!

The props interface correctly uses the readonly modifier as required by the coding guidelines.


38-44: LGTM!

The destructuring of directMessages improves readability and aligns with the refactor to expose pagination state more explicitly.


46-48: LGTM!

The reset logic correctly clears the fetch flag when pagination state changes, enabling subsequent fetches after completion.


50-57: LGTM!

The use of useEffectEvent for fetchNextPageIfNeeded is appropriate here—it creates a stable reference for the event handler while accessing the latest state, and the triple guard prevents duplicate fetches.


82-85: LGTM!

The memoization of wavesWithPinned is appropriate and the dependency array is correct.


132-152: LGTM!

The rendering logic correctly uses the refactored state:

  • wavesWithPinned is properly passed to UnifiedWavesListWaves
  • UnifiedWavesListLoader now receives both isFetching and isFetchingNextPage (addressing past review feedback)
  • UnifiedWavesListEmpty receives the appropriate list and loading states

59-79: Based on the investigation, I found that the sentinel element is always rendered with a static key, and the IntersectionObserver watches the element via a ref. The current dependency pattern (boolean list.length > 0) appears to be an intentional optimization to avoid recreating the observer on every list update.

However, there's a subtle fragility: if the sentinel DOM element is ever recreated (rather than repositioned), the observer could watch a stale node. This risk exists because the effect won't re-run when the list changes while remaining non-empty.

Please verify the sentinel rendering stability: Confirm that the sentinel element (rendered with key="sentinel") remains the same DOM node when the list changes while remaining non-empty. If there's any scenario where it could be recreated, the dependency array should include list or list.length instead of the boolean expression.

components/delegation/walletChecker/WalletChecker.tsx (6)

39-56: Well-structured helper function.

The display resolution logic correctly prioritizes from_display and falls back to to_display. The implementation is clear and handles the matching logic appropriately.


67-73: Excellent integration of useEnsResolution and React Query.

The ENS resolution hook provides clean state management for wallet input and address resolution. The delegations query is properly guarded with shouldFetchDelegations and follows React Query best practices with appropriate type annotations.

Also applies to: 92-103


133-179: Solid normalization and deduplication logic.

The setAllConsolidations callback correctly normalizes wallet consolidations, creates reciprocal entries for confirmed consolidations, and deduplicates entries. The empty dependency array is appropriate since the function has no external dependencies.


259-289: Well-designed memoized selectors.

activeDelegation efficiently searches through prioritized targets to find the active minting delegation. consolidationActions correctly identifies incomplete (non-reciprocal) consolidations. Both are properly memoized with complete dependency arrays.

Also applies to: 291-304


105-131: Proper query response handling and effect orchestration.

The effects correctly handle success/error states from all queries, with appropriate state updates and error recovery. The consolidated wallets refetch effect (lines 306-322) is properly guarded and only triggers when consolidations are loaded and present.

Also applies to: 206-216, 244-253, 306-322


351-395: Excellent ENS resolution handling.

The effect correctly handles ENS inputs by:

  • Detecting ENS format (.eth suffix)
  • Waiting for resolution to complete before validation
  • Handling both missing data and explicit errors
  • Clearing state appropriately for new checks

This properly addresses the past review concern about ENS inputs resolving before validation. The comprehensive dependency array ensures the effect runs whenever relevant state changes.

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 (3)
components/delegation/walletChecker/WalletChecker.tsx (2)

181-211: Consider logging the second fetch failure for better observability.

The silent catch at line 202 masks failures when fetching related consolidations. While returning firstData is reasonable, the error should be logged to aid debugging.

Apply this diff to add error logging:

         try {
           const secondResponse = (await fetchUrl(nextUrl)) as DBResponse;
           return [
             ...firstData,
             ...(secondResponse.data as WalletConsolidation[]),
           ];
         } catch {
+          console.error(`Failed to fetch consolidations for related wallet: ${newWallet}`);
           return firstData;
         }

262-264: Simplify by using the refetch function directly.

This wrapper adds no logic and refetch from useQuery is already stable. Remove the wrapper to reduce complexity.

Apply this diff:

-  const refetchConsolidatedWallets = useCallback(() => {
-    return refetchConsolidatedWalletsRaw();
-  }, [refetchConsolidatedWalletsRaw]);
+  const refetchConsolidatedWallets = refetchConsolidatedWalletsRaw;

Then update line 328 in dependencies and line 323 in the call site (no changes needed since the name remains the same).

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

86-140: Decouple pool type derivation from UI strings.

poolStringToPoolType reconstructs the enum by matching on subTitle. Because subTitle is meant purely for display, any copy tweak or future i18n pass (e.g. wrapping with a translator) will break the lookup, trigger the toast, and throw. It’s safer to recover the pool type from the source snapshots data instead of the presentation string.

You can eliminate the string-based reverse lookup and derive the type directly from the snapshot record, e.g.:

-    const poolStringToPoolType = (str: string): Pool => {
-      const poolType = Object.entries(POOL_TYPE_TO_STRING)
-        .find(([, value]) => value === str)
-        ?.at(0);
-      if (!poolType) {
-        setToasts({
-          type: "error",
-          messages: [`Unknown pool type: ${str}`],
-        });
-        throw new Error(`Unknown pool type: ${str}`);
-      }
-      return poolType as Pool;
-    };
     setSnapshotsToExclude(
       selectedOptions.map((o) => {
-        const snapshotType = poolStringToPoolType(o.subTitle ?? "");
+        const snapshot = snapshots.find(
+          (snapshotItem) => snapshotItem.id === o.value
+        );
+        if (!snapshot) {
+          setToasts({
+            type: "error",
+            messages: [`Unknown snapshot id: ${o.value}`],
+          });
+          throw new Error(`Unknown snapshot id: ${o.value}`);
+        }
+        const snapshotType = snapshot.poolType;
         const extraWallets: string[] =
           snapshotType === Pool.TOKEN_POOL
             ? []

(remember to add snapshots to the effect dependencies). This keeps the business logic tied to stable identifiers rather than UI text.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa855d4 and f64b139.

📒 Files selected for processing (2)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/delegation/walletChecker/WalletChecker.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
🧬 Code graph analysis (2)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (5)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
  • DistributionPlanSnapshot (55-60)
  • PhaseGroupSnapshotConfig (68-83)
  • PhaseGroupSnapshotConfigExcludeSnapshot (62-66)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (15)
components/delegation/walletChecker/WalletChecker.tsx (15)

3-12: LGTM: Imports align with refactor goals.

The new imports support the migration to hook-based ENS resolution and react-query data fetching.

Based on learnings


39-56: LGTM: Display resolution logic is correct.

The function correctly prioritizes from_display over to_display when resolving consolidation display names, which aligns with consolidation semantics.


64-73: LGTM: useEnsResolution integration is correct.

The hook is properly initialized with the query parameter and will handle ENS resolution for both directions (name→address and address→name).


92-103: LGTM: Delegations query follows react-query best practices.

The query is properly gated by shouldFetchDelegations and disables window focus refetching appropriately.

Based on learnings


105-131: LGTM: Delegation processing handles success and error cases correctly.

The effect properly filters sub-delegations and sets the loaded state in both success and error paths.


133-179: LGTM: Consolidation normalization correctly handles bidirectional relationships.

The callback properly deduplicates and creates reciprocal entries for confirmed consolidations, with appropriate memoization.


213-223: LGTM: Consolidations effect properly delegates normalization.

The effect correctly invokes setAllConsolidations for data transformation and handles errors appropriately.


225-249: LGTM: Consolidated wallets query uses manual refetch pattern correctly.

The disabled query with manual refetch allows control over when to fetch consolidated wallet details, and display resolution is properly integrated.


251-260: LGTM: Consolidated wallets effect follows consistent pattern.

Success and error cases are handled correctly with appropriate state updates.


266-296: LGTM: Active delegation search logic follows correct priority order.

The memoized selector properly searches for minting delegations across The Memes contract and all contracts, with appropriate fallback ordering.


298-311: LGTM: Consolidation actions correctly identify non-reciprocal relationships.

The filter logic properly detects incomplete consolidations by checking for the absence of reciprocal entries.


313-329: LGTM: Refetch effect properly manages consolidated wallet state.

The effect correctly triggers wallet refetch when consolidations change and handles the empty consolidations case appropriately.


358-402: LGTM: Validation effect correctly handles ENS resolution timing.

The effect properly waits for ENS lookups to complete before validating, preventing false "Invalid address" errors for ENS inputs. This addresses the concerns from previous reviews.


448-448: LGTM: Input handler correctly delegates to useEnsResolution.

The handler properly updates ENS resolution state when the user types.


465-465: LGTM: Clear handler correctly resets ENS resolution state.

Passing an empty string to handleWalletInputChange properly clears the ENS-resolved address.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

172-179: QueryKey includes array references—consider stability.

The queryKey includes snapshotsToExclude (array of objects) and currentSnapshotExtraWallets (array of strings). If these arrays are reconstructed with the same content but different references, React Query will treat them as different keys and refetch.

Since snapshotsToExclude is recomputed in the useEffect at line 86 whenever dependencies change, this behavior is likely intentional. However, if you notice unnecessary refetches, consider using a serialized representation (e.g., JSON.stringify) or stable references in the queryKey.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f64b139 and 3095ebe.

📒 Files selected for processing (5)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (5 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to {app,pages}/**/*.{ts,tsx} : Use NextJS features that match the current version
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
🧬 Code graph analysis (3)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (4)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
  • DistributionPlanSnapshot (55-60)
  • PhaseGroupSnapshotConfig (68-83)
  • PhaseGroupSnapshotConfigExcludeSnapshot (62-66)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistOperation (133-139)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
⏰ 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 (8)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx (1)

28-30: LGTM! WALLET_POOL handling properly added.

The new case for Pool.WALLET_POOL correctly sets the subtitle to "Wallets" and maintains consistency with the existing pool type handling pattern.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsx (1)

23-23: LGTM! Pool type broadened appropriately.

The change from a discriminated union to the broader Pool type aligns with the expanded pool type support (including WALLET_POOL) introduced across the PR.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (4)

26-30: LGTM! Centralized pool type mapping.

The POOL_TYPE_TO_STRING constant provides a clean, type-safe mapping from Pool enum values to display strings, eliminating scattered string literals.


40-48: LGTM! Props marked readonly per coding guidelines.

All props are now properly marked as readonly, following the established coding guidelines for this codebase.

As per coding guidelines.


89-98: LGTM! Robust error handling added.

The explicit check for unknown snapshot IDs with user-facing error toasts and thrown exceptions prevents silent failures when snapshot references become invalid.


167-201: LGTM! React Query properly implemented.

The implementation correctly addresses previous review feedback by:

  • Using react-query for data fetching per coding guidelines
  • Properly managing loading state with isUniqueWalletsCountLoading
  • Including appropriate dependencies in the queryKey
  • Guarding execution with shouldFetchUniqueWalletsCount

As per coding guidelines.

components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (2)

58-58: LGTM! Pool types broadened consistently.

The expansion from specific pool type unions to the broader Pool type in DistributionPlanSnapshot.poolType (line 58) and PhaseGroupSnapshotConfig.snapshotType (line 71) aligns with the WALLET_POOL support added throughout the PR.

Also applies to: 71-71


97-111: LGTM! Props interface with readonly modifiers.

The introduction of BuildPhaseFormConfigModalProps with readonly modifiers on all props follows the coding guidelines and improves type safety.

As per coding guidelines.

Comment thread components/delegation/walletChecker/WalletChecker.tsx
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/delegation/walletChecker/WalletChecker.tsx (1)

181-212: LGTM! Dual-fetch consolidation logic is sound.

The query correctly fetches from both the primary wallet and related wallet endpoints, with appropriate error handling for the secondary fetch. The console.error on line 203 provides useful debugging information.

Optional: Consider using a centralized error tracking solution instead of console.error for production visibility, though the current approach is acceptable for this use case.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (1)

138-159: LGTM! Well-optimized computation.

Proper use of useMemo for the expensive owner extraction and deduplication logic.

Minor: The owner extraction logic (lines 152-158) mirrors similar logic at lines 123-125. Consider extracting a helper function:

const extractOwnersFromTokens = (tokens: CustomTokenPoolParamsToken[] | undefined): string[] => {
  const owners = (tokens ?? [])
    .map((token) => token?.owner)
    .filter((owner: unknown): owner is string => typeof owner === "string")
    .map((owner) => owner.toLowerCase());
  return Array.from(new Set(owners));
};
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3095ebe and bc4161f.

📒 Files selected for processing (2)
  • components/delegation/walletChecker/WalletChecker.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (7 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
  • components/delegation/walletChecker/WalletChecker.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching

Applied to files:

  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx
🧬 Code graph analysis (2)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (5)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
  • DistributionPlanSnapshot (55-60)
  • PhaseGroupSnapshotConfig (68-83)
  • PhaseGroupSnapshotConfigExcludeSnapshot (62-66)
components/distribution-plan-tool/DistributionPlanToolContext.tsx (1)
  • DistributionPlanToolContext (86-105)
components/allowlist-tool/common/select-menu-multiple/AllowlistToolSelectMenuMultiple.tsx (1)
  • AllowlistToolSelectMenuMultipleOption (9-13)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • CustomTokenPoolParamsToken (147-150)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/delegation/walletChecker/WalletChecker.tsx (6)
helpers/Helpers.ts (2)
  • areEqualAddresses (149-154)
  • isValidEthAddress (222-223)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
services/6529api.ts (1)
  • fetchUrl (6-19)
entities/IDelegation.ts (2)
  • Delegation (10-21)
  • WalletConsolidation (29-36)
components/delegation/delegation-constants.ts (2)
  • SUB_DELEGATION_USE_CASE (73-77)
  • MINTING_USE_CASE (57-60)
constants.ts (2)
  • MEMES_CONTRACT (6-6)
  • DELEGATION_ALL_ADDRESS (36-37)
⏰ 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 (13)
components/delegation/walletChecker/WalletChecker.tsx (7)

39-56: LGTM! Clean helper function for consolidation display resolution.

The logic correctly prioritizes from_display and falls back to to_display, using early returns for efficiency.


64-73: LGTM! Proper integration of the useEnsResolution hook.

The hook integration centralizes ENS logic cleanly, with clear aliasing and appropriate configuration.


90-103: LGTM! React-query implementation follows best practices.

The query is properly guarded with shouldFetchDelegations, includes appropriate cache keys, and disables window focus refetch as expected for this use case.

As per coding guidelines


105-131: LGTM! Query response handling is comprehensive.

The effect correctly processes both success and error states, filters delegations appropriately, and ensures delegationsLoaded is always set.


133-179: LGTM! Consolidation normalization is well-implemented.

The callback correctly creates bidirectional entries for confirmed consolidations, properly deduplicates, and uses an appropriate empty dependency array since it has no external dependencies.


265-310: LGTM! Memoized computed values are efficient and correct.

Both activeDelegation and consolidationActions use proper memoization with complete dependency arrays. The active delegation search prioritizes correctly, and the consolidation actions filtering logic accurately identifies incomplete consolidations.


357-413: LGTM! Validation effect correctly handles ENS resolution.

The effect properly waits for ENS lookups to complete before validation, clears stale state on all error paths, and has complete dependencies. The logic addresses the concerns from previous review comments.

components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsx (6)

3-3: LGTM! Clean imports and centralized constant.

The new imports support the React Query refactor and memoization improvements. The POOL_TYPE_TO_STRING constant eliminates inline string logic for better maintainability.

Also applies to: 17-17, 23-30


40-48: LGTM! Props correctly marked readonly.

Follows coding guidelines for TypeScript props.

As per coding guidelines.


86-136: LGTM! Robust exclusion logic with proper error handling.

The snapshot lookup with error feedback (lines 89-98) prevents silent failures. Type-safe owner extraction from CustomTokenPoolParamsToken ensures correctness across pool types.


212-226: LGTM! Proper state synchronization.

The fallback logic ensures localUniqueWalletsCount always has a reasonable value, even on fetch errors.


261-261: LGTM! Correct loading state.

Properly wired to isUniqueWalletsCountLoading from React Query, addressing the previous hardcoded false issue.


161-210: ****

The hardcoding of excludeComponentWinners: [] on line 197 is correct and intentional. Based on the form step ordering in BuildPhaseFormConfigModal (lines 726-739), SNAPSHOT_EXCLUDE_OTHER_SNAPSHOTS executes before SNAPSHOT_EXCLUDE_COMPONENT_WINNERS. When this component runs, the user has not yet selected component winners, so config.excludeComponentWinners is always empty. The API call accurately reflects this state.

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 (2)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx (2)

12-16: Add readonly before props.

All props must be marked as readonly according to the coding guidelines.

As per coding guidelines.

Apply this diff:

 }: {
-  snapshot: DistributionPlanSnapshot;
-  selectedSnapshot: DistributionPlanSnapshot | null;
-  setSelectedSnapshot: (snapshot: DistributionPlanSnapshot) => void;
+  readonly snapshot: DistributionPlanSnapshot;
+  readonly selectedSnapshot: DistributionPlanSnapshot | null;
+  readonly setSelectedSnapshot: (snapshot: DistributionPlanSnapshot) => void;
 }) {

70-80: Replace inline SVG with FontAwesome icon.

The inline SVG checkmark violates the coding guidelines, which require using FontAwesome for icons in .tsx files.

As per coding guidelines.

Apply this diff:

+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faCheck } from "@fortawesome/free-solid-svg-icons";
       {isSelected && (
         <span className="tw-text-white tw-absolute tw-inset-y-0 tw-right-0 tw-flex tw-items-center tw-pr-4">
-          <svg
-            className="tw-h-5 tw-w-5 tw-text-white"
-            viewBox="0 0 20 20"
-            fill="currentColor"
-            aria-hidden="true">
-            <path
-              fillRule="evenodd"
-              d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
-              clipRule="evenodd"
-            />
-          </svg>
+          <FontAwesomeIcon icon={faCheck} className="tw-h-5 tw-w-5" />
         </span>
       )}
🧹 Nitpick comments (1)
components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (1)

30-58: Approve data removal; consider react-query useMutation for cleaner state management.

The change to ignore the data response is correct—phaseId is generated locally on Line 34, so the API response data isn't needed.

However, consider refactoring to use react-query's useMutation to eliminate manual isLoading state management and leverage built-in error handling, success callbacks, and query invalidation.

[As per coding guidelines]

Example refactor:

import { useMutation, useQueryClient } from '@tanstack/react-query';

const queryClient = useQueryClient();

const addPhaseMutation = useMutation({
  mutationFn: async (phaseId: string) => {
    const endpoint = `/allowlists/${distributionPlan.id}/operations`;
    return await distributionPlanApiPost({
      endpoint,
      body: {
        code: AllowlistOperationCode.ADD_PHASE,
        params: {
          id: phaseId,
          name: formValues.name,
          description: formValues.name,
        },
      },
    });
  },
  onSuccess: async () => {
    await fetchOperations(distributionPlan.id);
    setFormValues({ name: "" });
  },
});

const addPhase = async (): Promise<string | null> => {
  if (!distributionPlan) return null;
  const phaseId = getRandomObjectId();
  const result = await addPhaseMutation.mutateAsync(phaseId);
  return result.success ? phaseId : null;
};

Then use addPhaseMutation.isPending instead of isLoading.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a0ee9f and 9daf9bd.

📒 Files selected for processing (8)
  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (6 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx (2 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx (1 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx (3 hunks)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx (1 hunks)
  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx
  • components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx
  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching
📚 Learning: 2025-09-28T12:29:11.651Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.tsx : Use FontAwesome for icons

Applied to files:

  • components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx
🧬 Code graph analysis (2)
components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (1)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsx (3)
components/distribution-plan-tool/build-phases/BuildPhases.tsx (1)
  • BuildPhasesPhase (13-21)
services/distribution-plan-api.ts (1)
  • distributionPlanApiPost (64-96)
components/allowlist-tool/allowlist-tool.types.ts (1)
  • AllowlistOperation (133-139)
⏰ 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/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsx (1)

28-30: LGTM! Correct handling of WALLET_POOL.

The new case correctly handles the Pool.WALLET_POOL type and prevents the assertUnreachable from being called. The implementation follows the existing pattern and aligns with the broadened type support described in the PR summary.

components/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsx (1)

13-15: LGTM! Simplified context usage.

Removing setToasts is correct since error feedback is handled within the distributionPlanApiPost service layer via makeErrorToast. This simplification aligns with the broader refactor to reduce reliance on context-provided toast state.

components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsx (3)

4-5: LGTM! FontAwesome imports added correctly.

The imports properly introduce FontAwesome's copy icon and component, aligning with the coding guideline to use FontAwesome for icons.

As per coding guidelines


40-40: LGTM! Removed unused variable.

The change removes the unused copyState from the destructuring since the component manages its own copy state via the coping variable on line 41.


51-55: LGTM! FontAwesome icon correctly replaces inline SVG.

The change successfully replaces the inline SVG with FontAwesome's faCopy icon while preserving all functionality. The implementation properly uses TailwindCSS for styling and maintains the onClick handler for copy behavior.

As per coding guidelines

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

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
components/delegation/DelegationFormParts.tsx (2)

265-269: Consider capturing title in useEffectEvent for cleaner pattern.

The current useEffectEvent wraps onSetToast to avoid including it in the dependency array, but title is still passed as a parameter and included in the dependency array (line 321). You can simplify by capturing title directly inside emitToast, eliminating it from the dependency array.

-const emitToast = useEffectEvent(
-  (toast: { title: string; message: string }) => {
-    onSetToast(toast);
-  }
-);
+const emitToast = useEffectEvent((message: string) => {
+  onSetToast({ title, message });
+});

Then update the calls to pass only the message:

-emitToast({
-  title,
-  message: writeDelegation.error.message.split("Request Arguments")[0],
-});
+emitToast(writeDelegation.error.message.split("Request Arguments")[0]);

And remove title from the dependency array at line 321:

 }, [
   writeDelegation.error,
   writeDelegation.data,
   waitWriteDelegation.isLoading,
-  title,
+  emitToast,
 ]);

This fully leverages useEffectEvent to capture the latest title without triggering effect re-runs.


249-258: Optional: Destructuring all props is unnecessary.

Destructuring every prop at the top of the function doesn't add clarity here and just duplicates the prop names. Using props.title, props.validate, etc. directly is more concise.

-const {
-  title,
-  writeParams,
-  showCancel,
-  gasError,
-  validate,
-  onHide,
-  onSetToast,
-  submitBtnLabel,
-} = props;
+

Then reference props directly (e.g., props.title, props.validate()). This is purely a style choice.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9daf9bd and afcc9cd.

📒 Files selected for processing (1)
  • components/delegation/DelegationFormParts.tsx (9 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{ts,tsx}: Do not include any comments in the code
Use react-query for data fetching
Always add readonly before props

Files:

  • components/delegation/DelegationFormParts.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursorrules)

**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling

Files:

  • components/delegation/DelegationFormParts.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursorrules:0-0
Timestamp: 2025-09-28T12:29:11.651Z
Learning: Applies to **/*.{ts,tsx} : Use react-query for data fetching
🧬 Code graph analysis (1)
components/delegation/DelegationFormParts.tsx (2)
hooks/useEnsResolution.ts (1)
  • useEnsResolution (13-97)
helpers/AllowlistToolHelpers.ts (1)
  • getRandomObjectId (46-48)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
components/delegation/DelegationFormParts.tsx (1)

24-47: LGTM! Clean refactor to use centralized ENS resolution.

The component correctly delegates ENS resolution to the useEnsResolution hook and propagates the resolved address to the parent via the effect. The input binding to inputValue and handleInputChange from the hook is appropriate.

Comment thread components/delegation/DelegationFormParts.tsx
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Nov 5, 2025

@simo6529 simo6529 merged commit 9bbb63d into main Nov 5, 2025
8 checks passed
@simo6529 simo6529 deleted the lint-errors-v2 branch November 5, 2025 13:48
This was referenced Nov 6, 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