Conversation
WalkthroughStabilizes 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
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
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 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: Missingreadonlymodifier on props object; unusedconfigprop in destructuring.The component's props object is missing the
readonlykeyword as per coding guidelines. Additionally, theconfigproperty is declared in the type definition but is not destructured from the function parameters, making it unused.Apply this diff to add
readonlyand remove the unusedconfig: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
useEffectblock 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: Addreadonlymodifier to props per coding guidelines.The props should have the
readonlymodifier 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
uniqueWalletsCountByOperationsandloadingUniqueWalletsCountIdsare 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:
uniqueWalletsCountByOperationsis alwaysnullloadingUniqueWalletsCountIdsis always an empty arrayisLoadingUniqueWalletsCountis set once tofalseand never changes- The useEffect on lines 720-726 serves no purpose
This appears to be incomplete refactoring. Either:
- Remove the unused state variables and stop passing them to child components, or
- 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
_debouncedUniqueCountOpsis computed viauseDebouncebut 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
voteValueto be set to""or"-"using anas anycast (line 32), bypassing TypeScript's type safety. This creates a critical bug:
- When
voteValueis""or"-", the submit button becomes enabled (since"" !== 0)- Clicking submit passes this string value to the API as a rate (line 86)
- The API expects a
number, causing a runtime errorApply 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.
useReadContractsstays 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: VerifyuseEffectEventavailability in your React version.
useEffectEventis 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.tsxat 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.tsxandDelegationFormParts.tsx. This code should be extracted into a shared hook to improve maintainability.See the same issue flagged in
components/delegation/DelegationFormParts.tsxat lines 38-80.
🧹 Nitpick comments (14)
components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsx (1)
131-131: Replace staticloadingstate with constant.The
loadingstate is initialized tofalseand 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
Paginationcomponent.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
useCallbackto 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 makingpoolTypeToStringa constant outside the component.This mapping never changes, so using
useStateadds 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: Replaceanytype with proper typing.Using
anyfor 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 theoptionsarray 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, memoizingoptionswithuseMemowould improve performance by preventing unnecessary effect executions.Consider wrapping the
optionscalculation inuseMemo:- 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
useMemohook 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 theareEqualAddresseshelper.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:activeWaveIdis destructured but never used.The prop is aliased to
_activeWaveIdbut 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:activeWaveIdis destructured but never used.The prop is aliased to
_activeWaveIdbut 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
.tsxfiles. Consider replacing the inline SVG with a FontAwesome icon such asfaCopyfrom@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
updatedAddressfrom within thesetDelegationToInputcallback 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
useEnsResolutionin a file likehooks/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
fetchviafetchUrl, 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
📒 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.tsxcomponents/brain/feed/FeedScrollContainer.tsxcomponents/delegation/DelegationCenter.tsxcomponents/community/members-table/CommunityMembersTableHeaderSortableContent.tsxcomponents/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsxcomponents/brain/notifications/NotificationsFollowBtn.tsxcomponents/brain/left-sidebar/web/WebUnifiedWavesList.tsxcomponents/community/CommunityMembers.tsxcomponents/app-wallets/AppWallet.tsxcomponents/distribution-plan-tool/common/DistributionPlanWarnings.tsxcomponents/delegation/UpdateDelegation.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsxcomponents/brain/left-sidebar/waves/UnifiedWavesList.tsxcomponents/brain/my-stream/MyStreamWaveDesktopTabs.tsxcomponents/app-wallets/AppWalletsContext.tsxcomponents/delegation/CollectionDelegation.tsxcomponents/delegation/NewAssignPrimaryAddress.tsxcomponents/delegation/walletChecker/WalletChecker.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/brain/my-stream/MyStreamWaveFAQ.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/delegation/DelegationFormParts.tsxcomponents/cookies/CookieConsentContext.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
components/block-picker/advanced/BlockPickerAdvancedItemBlock.tsxcomponents/brain/feed/FeedScrollContainer.tsxcomponents/delegation/DelegationCenter.tsxcomponents/community/members-table/CommunityMembersTableHeaderSortableContent.tsxcomponents/distribution-plan-tool/create-phases/form/CreatePhasesForm.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/snapshots-table/FinalizeSnapshotsTableSnapshotTooltip.tsxcomponents/brain/notifications/NotificationsFollowBtn.tsxcomponents/brain/left-sidebar/web/WebUnifiedWavesList.tsxcomponents/community/CommunityMembers.tsxcomponents/app-wallets/AppWallet.tsxcomponents/distribution-plan-tool/common/DistributionPlanWarnings.tsxcomponents/delegation/UpdateDelegation.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsxcomponents/brain/left-sidebar/waves/UnifiedWavesList.tsxcomponents/brain/my-stream/MyStreamWaveDesktopTabs.tsxcomponents/app-wallets/AppWalletsContext.tsxcomponents/delegation/CollectionDelegation.tsxcomponents/delegation/NewAssignPrimaryAddress.tsxcomponents/delegation/walletChecker/WalletChecker.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/brain/my-stream/MyStreamWaveFAQ.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentConfigMeta.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/delegation/DelegationFormParts.tsxcomponents/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.tsxcomponents/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 acceptsComponentConfigMetaPropsbut 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
distributionPlanfrom 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
hasErrorsdirectly 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
setToastsfrom the context destructuring is good cleanup since it's not used in this component.
35-45: LGTM! Removed unused response data.Removing
datafrom the response destructuring is appropriate since only thesuccessboolean 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
distributionPlanApiPostservice.Please confirm whether:
- The guideline applies to mutations (POST operations) or only queries (GET operations)
- This pattern is acceptable or if there's a plan to migrate to React Query's
useMutationAs 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
AllowlistOperationCodeimport 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
waveprop 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
refto 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
loadPerformanceCookiesfunction is correctly memoized with an empty dependency array since it only manipulates the DOM and references the constantGTM_ID.
95-130: Correct memoization with appropriate dependencies.The
getCookieConsentfunction 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
consentcallback properly includes bothgetCookieConsentandsetToastin its dependency array, ensuring stable behavior while capturing all external references.
147-164: Dependencies correctly specified.The
rejectcallback properly includes bothgetCookieConsentandsetToastin its dependency array, mirroring the correct pattern used inconsent.
171-173: Correct dependency array for useEffect.Adding
getCookieConsentto the dependency array satisfies React Hook rules. SincegetCookieConsentis 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
fetchAppWalletsfunction 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
createAppWalletcallback properly includes bothappWalletsSupportedandfetchAppWalletsin its dependency array, ensuring the function captures the latest values while remaining stable across renders.
159-201: Dependencies correctly specified for wallet import.The
importAppWalletcallback properly includes bothappWalletsSupportedandfetchAppWalletsin its dependency array, mirroring the correct pattern used increateAppWallet.
203-216: Dependencies correctly specified for wallet deletion.The
deleteAppWalletcallback properly includes bothappWalletsSupportedandfetchAppWalletsin 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
convertSortByinuseCallbackprevents unnecessary recalculations of theparamsmemoized 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
useMemoprevents unnecessary query parameter re-derivations, and the dependency array correctly includes all referenced values.
105-119: LGTM! Properly memoized query string builder.The
useCallbackwith[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
paramsis already memoized.
171-180: Memoization and dependency fixes work together correctly.The
updateFieldscallback 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
setPagecallback 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
useEffectis 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_actionsfield is a required, non-nullable array in theApiProfileMinschema, 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
useEffectfrom the imports is correct since it's no longer used after convertingisEditingto a derived value.
26-26: Excellent simplification using derived state.Converting
isEditingfrom 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
useEffectEventis 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 -setAddressQueryfromuseStateis already stable.The concern is theoretically valid, but doesn't apply in this codebase. The
setNewPrimaryAddressQueryprop originates fromuseStateinapp/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 becauseuseStatesetters are inherently stable—no explicituseCallbackwrapping is needed.components/brain/direct-messages/DirectMessagesList.tsx (2)
33-53: Nice refactoring withuseEffectEventand localized state.The destructuring of
directMessagesproperties and the use offetchNextPageIfNeededwithuseEffectEventimproves code clarity and correctly excludes the stable callback from the dependency array (line 75). The guard logic insidefetchNextPageIfNeededalso 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
useEffectEventas a stable API, and the project uses React 19.2.0. The import ofuseEffectEventis 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
useEffectEventon 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
copyStatevariable 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
handleRedirectandhandleSeizeConnectClosedevent 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
useStatesetters (setNewDelegationToAddress) toDelegationFormDelegateAddressFormGroup, so the upstream dependency is stable. However, the actual issue exists at line 281 inDelegationFormDelegateAddressFormGroup: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 withuseCallbackor removed entirely by passingprops.setAddressdirectly.Likely an incorrect or invalid review comment.
components/delegation/walletChecker/WalletChecker.tsx (2)
114-281: LGTM: Solid memoization strategy.The use of
useCallbackanduseMemois 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 —useEffectEventis 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.
There was a problem hiding this comment.
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: Addreadonlymodifiers 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.
isDisabledis entirely derived frommaxMintsand doesn't need to be state. UsinguseState+useEffectfor derived values is an anti-pattern that adds unnecessary complexity and potential for stale state.Apply this diff to compute
isDisableddirectly:- 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: Addreadonlyprefix 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: Addreadonlyprefix 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
areEqualAddresseshelper 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
configurefunction simply callsonConfigureGroup()without any additional logic. PassonConfigureGroupdirectly 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 “Add another snapshot”, otherwise click “Configure Group”. </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: PreferuseMemofor derived options.The
optionsstate and its effect (lines 51-62) duplicate the initial calculation (lines 38-49). Consider usinguseMemoto derive options directly fromphases:- 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: DeriveexcludeComponentWinnersdirectly fromselectedOptions.The
excludeComponentWinnersstate 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
fullUrlconstant is recreated on every render. While string concatenation is inexpensive, for cleaner code you could either move it inside thequeryFnor wrap it inuseMemo.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,maxMintsis 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
poolTypeToStringvariable simply aliases thePOOL_TYPE_TO_STRINGconstant without adding value. Consider usingPOOL_TYPE_TO_STRINGdirectly 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 unnecessaryasync/await.The
setStatefunction is typically synchronous in React contexts. Theasync/awaithere is unnecessary and potentially misleading.- const applyDistributionPlan = useEffectEvent( - async (distributionPlan: AllowlistDescription) => { - await setState(distributionPlan); - } - ); + const applyDistributionPlan = useEffectEvent( + (distributionPlan: AllowlistDescription) => { + setState(distributionPlan); + } + );
33-36: Replacealert()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
makeErrorToastfrom the appropriate location.
39-66: Good cleanup pattern with minor inconsistency.The
isActiveflag correctly prevents state updates after unmount. However, the error path at line 50 callsredirectToEmma()without checkingisActive, while the catch block at line 56-58 does check it. For consistency, consider checkingisActivebefore 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:refetchConsolidatedWalletsshould be wrapped inuseCallback.The
refetchfunction fromuseQueryis stable, but wrapping it inuseCallbackwould 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
📒 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.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsxcomponents/delegation/UpdateDelegation.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/delegation/walletChecker/WalletChecker.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsxhooks/useEnsResolution.tscomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/delegation/CollectionDelegation.tsxcomponents/delegation/NewAssignPrimaryAddress.tsxcomponents/delegation/DelegationFormParts.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsxcomponents/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.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/brain/my-stream/votes/MyStreamWaveMyVoteInput.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeComponent.tsxcomponents/delegation/UpdateDelegation.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/delegation/walletChecker/WalletChecker.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/delegation/CollectionDelegation.tsxcomponents/delegation/NewAssignPrimaryAddress.tsxcomponents/delegation/DelegationFormParts.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsxcomponents/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
copyStatefrom the hook since the component manages its owncopingstate for UI feedback.
51-55: LGTM: FontAwesome icon implementation is correct.The replacement of inline SVG with
FontAwesomeIconaligns 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 (
nullforuniqueWalletsCountandfalseforisLoadingUniqueWalletsCount) 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
readonlymodifiers 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
useQuerywith proper queryKey, error handling viaisError, andkeepPreviousDatafor 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
handlePageChangecallback properly memoizes the page change logic with scroll-to-top behavior. The empty dependency array is correct sincesetPageis stable.components/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsx (1)
13-14: LGTM! Optional props with sensible defaults.Making
uniqueWalletsCountandisLoadingUniqueWalletsCountoptional with appropriate default values (nullandfalse) 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 aloadingstate (line 82), addressing the previous concerns about hardcodednulland disabled loading feedback. This properly restores the unique wallets count functionality.
128-130: LGTM!The type assertion for
CustomTokenPoolParamsTokencorrectly matches the interface definition and safely extracts theownerproperty from custom token pool tokens.
141-141: LGTM!The dependency array correctly removes
poolTypeToStringsince 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:
isActiveflag prevents race conditions and stale state updates- Early returns with proper cleanup when essential data is missing (lines 156-168)
getCustomTokenPoolWalletsuses proper type guards and deduplication (lines 170-188)- Loading state is correctly managed in
fetchUniqueWalletsCount- Success validation checks both
successflag 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 ofuseEffectEventfor navigation.This pattern correctly wraps the navigation logic in a stable event handler.
3-3: ✓ React version verified: 19.2.0 supportsuseEffectEvent.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
useEffectEventis 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
directMessagesimproves code readability throughout the component.
42-53: LGTM - Correct useEffectEvent usage.The reset effect and
fetchNextPageIfNeededimplementation usinguseEffectEventis 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 withuseEffectEvent) is intentionally not in the dependency array per React 19 patterns.
135-136: Past review comment addressed.The missing
isFetchingprop 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: DerivedisEditingis more efficient.Computing
isEditingdirectly fromvoteValue !== currentVoteValueeliminates 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
pendingAddresspattern 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
normalizeInputWithResolvedAddresshandles 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 touseEnsResolutionhook.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.
DelegationAddressInputnow leveragesuseEnsResolution, 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
enabledflag and separates regular delegations from sub-delegations in the success handler.
125-171: LGTM: Consolidation normalization handles reciprocals correctly.The
setAllConsolidationscallback correctly creates reciprocal entries for confirmed consolidations and deduplicates entries.
230-275: LGTM: Efficient memoization of derived state.Both
activeDelegationandconsolidationActionsuseuseMemoappropriately 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.
There was a problem hiding this comment.
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 missingreadonlymodifiers to props.The inline props type definition is missing
readonlymodifiers, 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}andisLoading={false}means the component will never display wallet count information or loading states, even thoughconfig.uniqueWalletsCountis available and could be used.Consider passing
config.uniqueWalletsCountinstead ofnull:<ComponentConfigMeta tags={[]} - walletsCount={null} - isLoading={false} + walletsCount={config.uniqueWalletsCount} + isLoading={false} />components/brain/direct-messages/DirectMessagesList.tsx (1)
59-79: Consider includingsentinelin the effect dependencies.The effect reads
sentinelandcontainerReffromlistRef.currentbut doesn't include them in the dependency array. Ifsentineldoesn't exist on the first effect run and the dependencies[hasNextPage, isFetchingNextPage]don't change, the observer won't be set up even whensentinelbecomes 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
📒 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.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/brain/left-sidebar/web/WebUnifiedWavesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsx__tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/delegation/UpdateDelegation.tsxhooks/useEnsResolution.tscomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/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.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/brain/left-sidebar/web/WebUnifiedWavesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentAddSpots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/FinalizeSnapshot.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/ComponentSelectRandomHolders.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsx__tests__/components/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.test.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/delegation/UpdateDelegation.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeComponentWinners.tsxcomponents/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/reactand@testing-library/user-eventfor 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.tsxcomponents/distribution-plan-tool/create-plan/CreatePlan.tsxcomponents/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.tsxeslint.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 (
nullforuniqueWalletsCount,falseforisLoadingUniqueWalletsCount) and add the requiredReadonly<>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
pluginsandrulesobjects 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
useCallbackand 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
readonlyfor both fields, following the coding guidelines for TypeScript files.
33-34: LGTM! Correctly derives state from query data.The component properly extracts
downloadsandtotalResultsfrom the query data using optional chaining and sensible defaults.
36-39: LGTM! Well-optimized page change handler.The
useCallbackhook 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'suseQuery. 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
readonlymodifiers 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
isDisabledvalue 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
optionschanges due to phases being updated: when a component is deleted from phases, line 73-75 filtersselectedOptionsto only include IDs that still exist in the currentoptionsarray. Stale IDs inconfig.excludeComponentWinnersare silently excluded fromselectedOptionswithout 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
baseConfigconstant provides a clean, DRY foundation for test cases and is correctly typed asPhaseGroupSnapshotConfig.
64-76: Test correctly validates new config-based API.The test properly creates a config variant with
uniqueWalletsCount: 42and verifies it's passed through correctly in the callback, which aligns with the component's new behavior of usingconfig.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_STRINGas a constant mapping eliminates unnecessary state management and improves maintainability.
142-162: Well-implemented memoization for extra wallets extraction.The memoized
currentSnapshotExtraWalletscorrectly handles custom token pool owner extraction with proper type safety usingCustomTokenPoolParamsToken, deduplication, and case normalization.
164-204: Excellent migration to react-query!The component now uses
useQueryfor 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
shouldFetchUniqueWalletsCountThis is a significant improvement over the previous hardcoded approach.
As per coding guidelines.
206-222: State synchronization effects handle all scenarios correctly.The three
useEffecthooks properly managelocalUniqueWalletsCountby:
- Resetting to
config.uniqueWalletsCountwhen not fetching- Updating with fetched data when available
- 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
FinalizeSnapshotPropswithreadonlymodifiers 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
nullforuniqueWalletsCountandfalseforisLoadingUniqueWalletsCountprovides sensible fallback behavior when these values aren't provided.
80-80: Simplified onClick handler improves readability.Directly calling
onConfigureGroupinstead 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
useMemoto avoid recreating the annotated array on every render. The dependency onlistensures 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 === 0on 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 supportsuseEffectEvent—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 ofwavesWithPinned. No issues found.
There was a problem hiding this comment.
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
localUniqueWalletsCountare 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
fetchUrlcall fails, the entire query fails and users lose thefirstDataresults. 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
📒 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.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/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.tsxcomponents/brain/direct-messages/DirectMessagesList.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/community-downloads/CommunityDownloadsComponent.tsxcomponents/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.tsxcomponents/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: keepPreviousDataprovides smooth pagination UX- ✅
handlePageChangeproperly memoized withuseCallback- ✅
readonlymodifiers on props per coding guidelines- ✅ Clean derived state without manual synchronization
The loading check
isLoading && !datais particularly well-thought-out: it shows the loading indicator only on initial fetch, while subsequent page changes show stale data fromplaceholderDatafor 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
useMemoto 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
phasesas the dependency, which will prevent unnecessary recalculations when other state changes.
119-125: LGTM: Proper memoization of excludeComponentWinners.The derived
excludeComponentWinnersarray is correctly memoized based onselectedOptions, improving performance by avoiding redundant filtering operations.
63-83: LGTM: Robust synchronization logic.The effect correctly synchronizes the
config.excludeComponentWinnerswithselectedOptions, 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
excludeComponentWinnersandconfig.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_STRINGconstant provides a centralized mapping for pool types, improving maintainability. IncludingWALLET_POOLprovides defensive coverage for potential future use.
3-3: LGTM: Appropriate imports for react-query implementation.The addition of
useMemo,CustomTokenPoolParamsToken,distributionPlanApiPost, anduseQueryimports 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
snapshotsToExcludewith proper handling for different pool types. The token owner extraction forCUSTOM_TOKEN_POOLcorrectly accesses theownerproperty fromCustomTokenPoolParamsToken, and error handling is appropriate.
142-162: LGTM: Proper memoization of current snapshot owners.The
currentSnapshotExtraWalletsmemo 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
useQueryimplementation 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
localUniqueWalletsCountandisUniqueWalletsCountLoadingto provide appropriate functionality and user feedback.Also applies to: 254-258
components/brain/direct-messages/DirectMessagesList.tsx (8)
3-9: LGTM!The new imports (
useEffectEventanduseMemo) are appropriate for the sentinel-based pagination refactor and memoization pattern introduced in this file.
24-26: LGTM!The props interface correctly uses the
readonlymodifier as required by the coding guidelines.
38-44: LGTM!The destructuring of
directMessagesimproves 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
useEffectEventforfetchNextPageIfNeededis 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
wavesWithPinnedis appropriate and the dependency array is correct.
132-152: LGTM!The rendering logic correctly uses the refactored state:
wavesWithPinnedis properly passed toUnifiedWavesListWavesUnifiedWavesListLoadernow receives bothisFetchingandisFetchingNextPage(addressing past review feedback)UnifiedWavesListEmptyreceives the appropriatelistand 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 (booleanlist.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 includelistorlist.lengthinstead of the boolean expression.components/delegation/walletChecker/WalletChecker.tsx (6)
39-56: Well-structured helper function.The display resolution logic correctly prioritizes
from_displayand falls back toto_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
shouldFetchDelegationsand follows React Query best practices with appropriate type annotations.Also applies to: 92-103
133-179: Solid normalization and deduplication logic.The
setAllConsolidationscallback 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.
activeDelegationefficiently searches through prioritized targets to find the active minting delegation.consolidationActionscorrectly 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 (
.ethsuffix)- 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.
There was a problem hiding this comment.
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
firstDatais 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
refetchfrom 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.
poolStringToPoolTypereconstructs the enum by matching onsubTitle. BecausesubTitleis 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 sourcesnapshotsdata 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
snapshotsto 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
📒 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.tsxcomponents/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.tsxcomponents/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_displayoverto_displaywhen 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
shouldFetchDelegationsand 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
setAllConsolidationsfor 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
handleWalletInputChangeproperly clears the ENS-resolved address.
There was a problem hiding this comment.
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
queryKeyincludessnapshotsToExclude(array of objects) andcurrentSnapshotExtraWallets(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
snapshotsToExcludeis recomputed in theuseEffectat 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
📒 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.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/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.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshot.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/SnapshotExcludeOtherSnapshots.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/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_POOLcorrectly 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
Pooltype aligns with the expanded pool type support (includingWALLET_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_STRINGconstant provides a clean, type-safe mapping fromPoolenum 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-queryfor data fetching per coding guidelines- Properly managing loading state with
isUniqueWalletsCountLoading- Including appropriate dependencies in the
queryKey- Guarding execution with
shouldFetchUniqueWalletsCountAs 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
Pooltype inDistributionPlanSnapshot.poolType(line 58) andPhaseGroupSnapshotConfig.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
BuildPhaseFormConfigModalPropswithreadonlymodifiers on all props follows the coding guidelines and improves type safety.As per coding guidelines.
There was a problem hiding this comment.
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
useMemofor 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
📒 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.tsxcomponents/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.tsxcomponents/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_displayand falls back toto_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
delegationsLoadedis 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
activeDelegationandconsolidationActionsuse 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_STRINGconstant 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
CustomTokenPoolParamsTokenensures correctness across pool types.
212-226: LGTM! Proper state synchronization.The fallback logic ensures
localUniqueWalletsCountalways has a reasonable value, even on fetch errors.
261-261: LGTM! Correct loading state.Properly wired to
isUniqueWalletsCountLoadingfrom React Query, addressing the previous hardcodedfalseissue.
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_SNAPSHOTSexecutes beforeSNAPSHOT_EXCLUDE_COMPONENT_WINNERS. When this component runs, the user has not yet selected component winners, soconfig.excludeComponentWinnersis always empty. The API call accurately reflects this state.Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
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: Addreadonlybefore props.All props must be marked as
readonlyaccording 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
.tsxfiles.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-queryuseMutationfor cleaner state management.The change to ignore the
dataresponse is correct—phaseIdis generated locally on Line 34, so the API response data isn't needed.However, consider refactoring to use react-query's
useMutationto eliminate manualisLoadingstate 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.isPendinginstead ofisLoading.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/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.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/component-config/select-snapshot/SelectSnapshotDropdownListItem.tsxcomponents/distribution-plan-tool/build-phases/build-phase/form/BuildPhaseFormConfigModal.tsxcomponents/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_POOLtype and prevents theassertUnreachablefrom 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
setToastsis correct since error feedback is handled within thedistributionPlanApiPostservice layer viamakeErrorToast. 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
copyStatefrom the destructuring since the component manages its own copy state via thecopingvariable on line 41.
51-55: LGTM! FontAwesome icon correctly replaces inline SVG.The change successfully replaces the inline SVG with FontAwesome's
faCopyicon while preserving all functionality. The implementation properly uses TailwindCSS for styling and maintains the onClick handler for copy behavior.As per coding guidelines
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
components/delegation/DelegationFormParts.tsx (2)
265-269: Consider capturingtitleinuseEffectEventfor cleaner pattern.The current
useEffectEventwrapsonSetToastto avoid including it in the dependency array, buttitleis still passed as a parameter and included in the dependency array (line 321). You can simplify by capturingtitledirectly insideemitToast, 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
titlefrom the dependency array at line 321:}, [ writeDelegation.error, writeDelegation.data, waitWriteDelegation.isLoading, - title, + emitToast, ]);This fully leverages
useEffectEventto capture the latesttitlewithout 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
📒 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
useEnsResolutionhook and propagates the resolved address to the parent via the effect. The input binding toinputValueandhandleInputChangefrom the hook is appropriate.
|



Summary by CodeRabbit
Bug Fixes
Refactor
Style