Conversation
Signed-off-by: prxt6529 <prxt@6529.io>
WalkthroughAdds a transfer subsystem (state, selection UI, panel, modal, per-item components) integrated across collected/token pages; rewrites iterative paginated API helper with generics; introduces new constants, enums, hooks, scrollable tabs/filters refactors, and broad test/provider updates. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User
participant UI as Transfer UI\n(Toggle/Single/Panel)
participant State as TransferState\n(Context)
participant Modal as TransferModal
participant Chain as Smart Contract
participant Connect as SeizeConnect
User->>UI: Click Transfer Toggle
alt not connected
UI->>Connect: seizeConnect()
Connect-->>UI: connected
end
UI->>State: setEnabled(true)
User->>UI: Select items / adjust qty
UI->>State: toggleSelect / incQty / decQty
State-->>UI: selection & totals update
User->>UI: Click Continue
UI->>Modal: open(selected items)
Modal->>Modal: recipient selection & review
User->>Modal: confirm transfer
Modal->>Chain: submit ERC721/ERC1155 tx(s)
Chain-->>Modal: tx hash / receipt
Modal->>UI: onClose({completed:true})
UI->>State: clear() / setEnabled(false)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 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)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (2)**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursorrules)
Files:
**/*.tsx📄 CodeRabbit inference engine (.cursorrules)
Files:
🧠 Learnings (2)📚 Learning: 2025-09-28T12:29:11.651ZApplied to files:
📚 Learning: 2025-09-28T12:29:11.651ZApplied to files:
⏰ 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)
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: 5
🧹 Nitpick comments (6)
components/user/collected/transfer/TransferState.tsx (1)
45-45: Mark component props as readonlyAdd readonly to TransferProvider props to follow project conventions.
As per coding guidelines
-export function TransferProvider({ children }: { children: React.ReactNode }) { +export function TransferProvider({ children }: { readonly children: React.ReactNode }) {components/user/collected/UserPageCollected.tsx (1)
471-471: Remove JSX comments in TSX filesGuideline: no comments in TS/TSX. Remove these inline comments.
As per coding guidelines
- {/* small control bar with Transfer toggle */} <div className="tw-mt-3 tw-flex tw-justify-end"> <TransferToggle /> </div> @@ - {/* appears only when transfer is enabled */} <TransferPanel />Also applies to: 488-488
components/user/collected/transfer/TransferPanel.tsx (1)
14-17: Remove unused helperkeyToLabel is unused. Delete to avoid dead code.
- const keyToLabel = (key: string) => { - const [collection, tokenId] = key.split(":"); - return `${collection} #${tokenId}`; - };components/user/collected/cards/UserPageCollectedCard.tsx (3)
131-144: Add visible focus styles for keyboard users on the selectable wrapperImprove accessibility by adding focus-visible ring to the role="button" wrapper.
- <div - className="tw-no-underline" + <div + className="tw-no-underline tw-outline-none focus:tw-ring-2 focus:tw-ring-emerald-400/60" role="button" tabIndex={0}
59-63: Improve image a11y and performanceUse a descriptive alt and enable lazy loading.
- <img - src={card.img} - alt={card.collection} - className="tw-bg-transparent tw-max-w-full tw-max-h-full tw-h-auto tw-w-auto tw-mx-auto tw-object-contain" - /> + <img + src={card.img} + alt={`${collectionMeta.label} #${card.token_id} — ${card.token_name}`} + loading="lazy" + decoding="async" + className="tw-bg-transparent tw-max-w-full tw-max-h-full tw-h-auto tw-w-auto tw-mx-auto tw-object-contain" + />Optional: consider next/image for optimization if compatible with your image sources.
18-22: Make onToggle required in select mode via discriminated union propsEnforce at the type level that onToggle and selected are provided when interactiveMode is "select".
type BaseProps = { readonly card: CollectedCard; readonly showDataRow: boolean; readonly copiesMax?: number; readonly qtySelected?: number; }; type LinkProps = BaseProps & { readonly interactiveMode?: "link"; }; type SelectProps = BaseProps & { readonly interactiveMode: "select"; readonly selected: boolean; readonly onToggle: () => void; }; export default function UserPageCollectedCard(props: LinkProps | SelectProps) { // narrow with props.interactiveMode === 'select' }As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
components/user/collected/UserPageCollected.tsx(3 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)components/user/collected/cards/UserPageCollectedCards.tsx(2 hunks)components/user/collected/transfer/TransferPanel.tsx(1 hunks)components/user/collected/transfer/TransferState.tsx(1 hunks)components/user/collected/transfer/TransferToggle.tsx(1 hunks)services/auth/auth.utils.ts(0 hunks)
💤 Files with no reviewable changes (1)
- services/auth/auth.utils.ts
🧰 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 propsFollow existing code style and naming conventions
Files:
components/user/collected/transfer/TransferState.tsxcomponents/user/collected/transfer/TransferToggle.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxcomponents/user/collected/transfer/TransferPanel.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
components/user/collected/transfer/TransferState.tsxcomponents/user/collected/transfer/TransferToggle.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxcomponents/user/collected/transfer/TransferPanel.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx
🧬 Code graph analysis (5)
components/user/collected/transfer/TransferToggle.tsx (1)
components/user/collected/transfer/TransferState.tsx (1)
useTransfer(157-161)
components/user/collected/UserPageCollected.tsx (4)
components/user/collected/transfer/TransferState.tsx (1)
TransferProvider(45-155)components/user/collected/transfer/TransferToggle.tsx (1)
TransferToggle(5-23)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(9-83)components/user/collected/transfer/TransferPanel.tsx (1)
TransferPanel(8-128)
components/user/collected/cards/UserPageCollectedCards.tsx (2)
components/user/collected/transfer/TransferState.tsx (2)
useTransfer(157-161)buildTransferKey(164-175)components/user/collected/cards/UserPageCollectedCard.tsx (1)
UserPageCollectedCard(6-154)
components/user/collected/transfer/TransferPanel.tsx (1)
components/user/collected/transfer/TransferState.tsx (1)
useTransfer(157-161)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(382-391)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
components/user/collected/cards/UserPageCollectedCards.tsx (1)
24-65: Transfer-state wiring looks goodClean integration: stable key, selected/qty derivation, and responsive grid are correct.
Signed-off-by: prxt6529 <prxt@6529.io>
|
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/[user]/_lib/userTabPageFactory.tsx (1)
14-21: Addreadonlybefore props per coding guidelines.The coding guidelines state "Always add readonly before props" for TypeScript files.
As per coding guidelines.Apply this diff:
-type TabProps = { profile: ApiIdentity }; +type TabProps = { readonly profile: ApiIdentity }; type FactoryArgs = { - subroute: string; - metaLabel: string; - Tab: (props: TabProps) => React.JSX.Element; - enableTransfer?: boolean; + readonly subroute: string; + readonly metaLabel: string; + readonly Tab: (props: TabProps) => React.JSX.Element; + readonly enableTransfer?: boolean; };
♻️ Duplicate comments (6)
components/user/collected/transfer/TransferToggle.tsx (1)
29-49: Restore the FontAwesome toggle icon and expose pressed stateThe toggle still renders a raw ⇄ glyph and lacks
aria-pressed, violating our TSX guidelines (FontAwesome only, accessible state). Please reinstate the FontAwesome import/usage and bindaria-pressed={t.enabled}so assistive tech reads the toggle correctly.import { useEffect, useRef } from "react"; import { useTransfer } from "./TransferState"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faRightLeft } from "@fortawesome/free-solid-svg-icons"; @@ - <button - type="button" - onClick={() => { + <button + type="button" + aria-pressed={t.enabled} + onClick={() => { @@ - <span aria-hidden>⇄</span> + <FontAwesomeIcon + icon={faRightLeft} + aria-hidden="true" + className="tw-h-4 tw-w-4" + />components/user/collected/transfer/TransferPanel.tsx (1)
84-114: Swap text glyphs for FontAwesome icons in quantity & remove controlsPer the repo rule, we must not ship raw “-”, “+”, or “×” glyphs. The quantity stepper and remove button need FontAwesome icons (and we already import that library elsewhere). Please update all three controls accordingly.
-import { useEffect, useState } from "react"; -import TransferModal from "./TransferModal"; -import { useTransfer } from "./TransferState"; +import { useEffect, useState } from "react"; +import TransferModal from "./TransferModal"; +import { useTransfer } from "./TransferState"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { + faMinus, + faPlus, + faXmark, +} from "@fortawesome/free-solid-svg-icons"; @@ - <button + <button type="button" className="tw-inline-flex tw-items-center tw-justify-center tw-h-6 tw-w-6 tw-rounded-full tw-bg-white tw-text-black tw-font-medium hover:tw-bg-[#ddd] tw-text-lg tw-p-0 tw-border-0 disabled:tw-opacity-50 disabled:tw-cursor-not-allowed" onClick={() => t.decQty(it.key)} disabled={qty <= 1} aria-label="Decrease"> - - + <FontAwesomeIcon icon={faMinus} aria-hidden="true" /> </button> @@ - <button + <button type="button" className="tw-inline-flex tw-items-center tw-justify-center tw-h-6 tw-w-6 tw-rounded-full tw-bg-white tw-text-black tw-font-medium hover:tw-bg-[#ddd] tw-text-lg tw-p-0 tw-border-0 disabled:tw-opacity-50 disabled:tw-cursor-not-allowed" onClick={() => t.incQty(it.key)} disabled={qty >= max} aria-label="Increase"> - + + <FontAwesomeIcon icon={faPlus} aria-hidden="true" /> </button> @@ - <button + <button type="button" className="tw-inline-flex tw-items-center tw-justify-center tw-h-6 tw-w-6 tw-rounded-full tw-bg-[#ef4444] tw-font-medium tw-text-white hover:tw-bg-[#d92b2b] tw-text-lg tw-p-0 tw-border-0" onClick={() => t.unselect(it.key)} aria-label="Remove"> - × + <FontAwesomeIcon icon={faXmark} aria-hidden="true" /> </button>components/user/collected/cards/UserPageCollectedCards.tsx (1)
51-80: Coalesce seized_count passed to the formatter
card.seized_countisnumber | null, so the current call violates the formatter signature and can crash when the value is null. Coalesce before passing it in.- const max = Math.max(1, Number(card.seized_count ?? 1)); + const max = Math.max(1, Number(card.seized_count ?? 1)); @@ - copiesMax={max} + copiesMax={max}components/user/collected/cards/UserPageCollectedCard.tsx (3)
49-134: Fix checkbox toggle bugs & align with Tailwind prefixClicking the checkbox fires twice (wrapper
onClick+ checkbox bubbling) and the classes ignore ourtw-prefix. DroponSelect, stop propagation on the checkbox/label, and use thetw-utilities so selection works.- {interactiveMode === "select" && ( + {interactiveMode === "select" && ( <div className="tw-pt-2 tw-flex tw-items-center tw-justify-center tw-gap-x-2"> <input checked={selected} id={`${card.collection}-${card.token_id}`} type="checkbox" - className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" - onSelect={onToggle} - onChange={onToggle} + className="tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded-sm focus:tw-ring-2 focus:tw-ring-blue-500 dark:tw-focus:tw-ring-blue-600 dark:tw-ring-offset-gray-800 dark:tw-bg-gray-700 dark:tw-border-gray-600" + onChange={onToggle} + onClick={(e) => e.stopPropagation()} /> - {contractType === ContractType.ERC1155 ? ( - <span className="tw-text-sm tw-font-medium"> + {contractType === ContractType.ERC1155 ? ( + <label + htmlFor={`${card.collection}-${card.token_id}`} + className="tw-text-sm tw-font-medium" + onClick={(e) => e.stopPropagation()}> {selected ? `Selected ${qtySelected} / ${copiesMax}` : copiesMax > 1 ? `Select (up to ${copiesMax})` : "Select"} - </span> + </label> ) : ( - <span className="tw-text-sm tw-font-medium"> - {selected ? "Selected" : "Select"} - </span> + <label + htmlFor={`${card.collection}-${card.token_id}`} + className="tw-text-sm tw-font-medium" + onClick={(e) => e.stopPropagation()}> + {selected ? "Selected" : "Select"} + </label> )} </div> )}
81-87: Pass a number to formatNumberWithCommasOrDash
card.seized_countcan be null; the helper expects a number and will misbehave. Coalesce before formatting.- <span className="tw-text-sm min-[1200px]:tw-text-md tw-font-medium tw-text-iron-400"> - {formatNumberWithCommasOrDash(card.seized_count)}x - </span> + <span className="tw-text-sm min-[1200px]:tw-text-md tw-font-medium tw-text-iron-400"> + {formatNumberWithCommasOrDash(card.seized_count ?? 0)}x + </span>
49-147: Remove inline comments per TSX guidelineLines like
// shared card bodyviolate the “no comments in TS/TSX” rule. Delete the inline comments; rely on descriptive naming instead.
🧹 Nitpick comments (8)
constants.ts (1)
7-7: Remove commented-out code.Commented-out code should be removed rather than left in the codebase. Version control preserves the history if needed.
Apply this diff:
-// const MANIFOLD_PROXY = "0x26bbea7803dcac346d5f5f135b57cf2c752a02be";entities/IProfile.ts (1)
387-395: UseContractTypeinstead ofstringfor stronger type safety.The value type should be
ContractTyperather thanstringto leverage the enum and catch type errors at compile time.Apply this diff:
export const COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE: Record< CollectedCollectionType, - string + ContractType > = { [CollectedCollectionType.MEMES]: ContractType.ERC1155, [CollectedCollectionType.NEXTGEN]: ContractType.ERC721, [CollectedCollectionType.GRADIENTS]: ContractType.ERC721, [CollectedCollectionType.MEMELAB]: ContractType.ERC1155, };components/user/collected/transfer/TransferModalPfp.tsx (1)
16-21: Consider handling stale updates from async IPFS resolution.If the
srcprop changes while the previous asyncresolveIpfsUrlcall is in flight, the state update from the old call could overwrite the newer resolution. While unlikely to cause issues in practice for this use case, consider tracking whether the effect is still current.Example pattern:
useEffect(() => { + let cancelled = false; (async () => { const newSrc = await resolveIpfsUrl(src); - setResolved(newSrc); + if (!cancelled) setResolved(newSrc); })(); + return () => { cancelled = true; }; }, [src]);components/user/collected/transfer/TransferModal.tsx (5)
311-318: Remove any-cast “walletClientLocal” shim; use walletClient directlyThe extra destructuring via any is unnecessary and brittle. Use walletClient as returned by useWalletClient.
- const { data: walletClientLocal } = { data: walletClient } as any; - - if (!walletClientLocal) { + if (!walletClient) { setErrorMsg("Wallet not ready. Please reconnect."); setFlow("error"); setRetryable(true); return; }- const hash = await walletClientLocal.writeContract(request); + const hash = await walletClient.writeContract(request);- const hash = await walletClientLocal.writeContract(request); + const hash = await walletClient.writeContract(request);Also applies to: 340-344, 358-363
370-377: Wait for receipts in parallel to improve UXWaiting sequentially extends total wait time. Use Promise.all.
- // Wait for all receipts - for (const h of hashes) { - await publicClient.waitForTransactionReceipt({ - hash: h.hash as `0x${string}`, - }); - } + await Promise.all( + hashes.map((h) => + publicClient.waitForTransactionReceipt({ + hash: h.hash as `0x${string}`, + }) + ) + );
378-392: Retryable detection can be stale due to state readUsing txHashes.length from state inside catch may not reflect hashes produced earlier in the try. Prefer deriving from local progress (e.g., track a boolean when at least one write returns) or move hashes declaration outside try/catch.
If you want to verify current behavior, add a temporary console trace around the writeContract calls and the catch to confirm whether txHashes is still 0 when an error occurs after some writes.
697-713: Optional: dedupe block explorer link renderingThe three list renderings for submitted/success/error are nearly identical. Consider extracting a small helper to render the list to reduce duplication.
Also applies to: 715-737, 738-759
404-443: Optional: Add Escape-to-close to improve accessibilityHandle Escape key to close when allowed (not during wallet/submitted).
useEffect(() => { if (!open) return; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape" && flow !== "wallet" && flow !== "submitted") handleClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [open, flow, handleClose]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
app/[user]/_lib/userTabPageFactory.tsx(3 hunks)app/[user]/collected/page.tsx(1 hunks)components/user/collected/UserPageCollected.tsx(9 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)components/user/collected/cards/UserPageCollectedCards.tsx(2 hunks)components/user/collected/transfer/TransferModal.tsx(1 hunks)components/user/collected/transfer/TransferModalPfp.tsx(1 hunks)components/user/collected/transfer/TransferPanel.tsx(1 hunks)components/user/collected/transfer/TransferState.tsx(1 hunks)components/user/collected/transfer/TransferToggle.tsx(1 hunks)constants.ts(1 hunks)entities/IProfile.ts(2 hunks)enums.ts(1 hunks)next.config.mjs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{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 propsFollow existing code style and naming conventions
Files:
app/[user]/collected/page.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxentities/IProfile.tscomponents/user/collected/transfer/TransferModal.tsxenums.tsapp/[user]/_lib/userTabPageFactory.tsxcomponents/user/collected/transfer/TransferPanel.tsxconstants.tscomponents/user/collected/transfer/TransferModalPfp.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/user/collected/transfer/TransferToggle.tsxcomponents/user/collected/transfer/TransferState.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
app/[user]/collected/page.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxcomponents/user/collected/transfer/TransferModal.tsxapp/[user]/_lib/userTabPageFactory.tsxcomponents/user/collected/transfer/TransferPanel.tsxcomponents/user/collected/transfer/TransferModalPfp.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/user/collected/transfer/TransferToggle.tsxcomponents/user/collected/transfer/TransferState.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx
{app,pages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use NextJS features that match the current version
Files:
app/[user]/collected/page.tsxapp/[user]/_lib/userTabPageFactory.tsx
app/**
📄 CodeRabbit inference engine (AGENTS.md)
All new Next.js pages must be created under the
app/directory
Files:
app/[user]/collected/page.tsxapp/[user]/_lib/userTabPageFactory.tsx
app/**/{page,layout}.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Routes in
app/should export agenerateMetadatafunction usinggetAppMetadata
Files:
app/[user]/collected/page.tsx
🧬 Code graph analysis (9)
components/user/collected/cards/UserPageCollectedCards.tsx (3)
components/user/collected/transfer/TransferState.tsx (2)
useTransfer(158-162)buildTransferKey(165-176)components/user/collected/cards/UserPageCollectedCard.tsx (1)
UserPageCollectedCard(7-160)entities/IProfile.ts (2)
COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE(387-395)COLLECTED_COLLECTION_TYPE_TO_CONTRACT(377-385)
entities/IProfile.ts (1)
constants.ts (4)
MEMES_CONTRACT(5-5)NEXTGEN_CONTRACT(6-6)GRADIENT_CONTRACT(10-10)MEMELAB_CONTRACT(11-11)
components/user/collected/transfer/TransferModal.tsx (5)
components/user/collected/transfer/TransferState.tsx (1)
useTransfer(158-162)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/user/collected/transfer/TransferModalPfp.tsx (1)
TransferModalPfp(7-36)
app/[user]/_lib/userTabPageFactory.tsx (2)
components/user/collected/transfer/TransferState.tsx (1)
TransferProvider(46-156)components/user/layout/UserPageLayout.tsx (1)
UserPageLayout(17-73)
components/user/collected/transfer/TransferPanel.tsx (3)
components/user/collected/transfer/TransferState.tsx (1)
useTransfer(158-162)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/user/collected/transfer/TransferModal.tsx (1)
TransferModal(53-814)
components/user/collected/transfer/TransferModalPfp.tsx (1)
components/ipfs/IPFSContext.tsx (1)
resolveIpfsUrl(67-77)
components/user/collected/UserPageCollected.tsx (7)
hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/user/collected/transfer/TransferState.tsx (1)
useTransfer(158-162)components/user/collected/transfer/TransferToggle.tsx (1)
TransferToggle(7-52)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(14-99)components/user/collected/transfer/TransferPanel.tsx (1)
TransferPanel(9-154)
components/user/collected/transfer/TransferToggle.tsx (2)
components/user/collected/transfer/TransferState.tsx (1)
useTransfer(158-162)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (13)
constants.ts (1)
11-14: LGTM!The new exported constants are correctly formatted and will support the transfer functionality introduced in this PR.
components/user/collected/transfer/TransferState.tsx (5)
6-15: LGTM!The
TransferItemtype is well-structured with appropriate optional fields for transfer metadata.
42-44: LGTM!The clamp utility is correctly implemented and will ensure quantity values stay within bounds.
52-151: LGTM!The transfer state management API is comprehensive and correctly implemented:
- Selection state uses immutable Map updates
- Quantity operations properly clamp to [1, max]
- Max defaults to at least 1 to prevent division by zero or invalid ranges
- Memoization on
[enabled, selected]is appropriate
158-162: LGTM!The hook correctly enforces usage within a TransferProvider by throwing an error when context is null.
164-176: LGTM!The key-building logic handles null/undefined values appropriately and provides stable keys for the transfer state.
app/[user]/collected/page.tsx (1)
8-8: LGTM!Enabling transfer functionality for the Collected page is straightforward and aligns with the broader transfer feature set introduced in this PR.
next.config.mjs (1)
123-123: LGTM!Adding the IPFS domain to the image optimization whitelist enables rendering of IPFS-hosted assets in the transfer UI components.
enums.ts (1)
189-192: LGTM!The
ContractTypeenum provides type-safe references to the two token standards used in the transfer workflow.entities/IProfile.ts (2)
1-7: LGTM!The import updates correctly bring in the new contract constants and
ContractTypeenum needed for the mappings.
377-385: LGTM!The mapping from collection types to contract addresses is correctly implemented and aligns with the constants defined in
constants.ts.app/[user]/_lib/userTabPageFactory.tsx (1)
60-68: LGTM!The conditional rendering logic correctly wraps the Tab component with TransferProvider when transfer functionality is enabled.
components/user/collected/transfer/TransferModalPfp.tsx (1)
23-35: LGTM!The loading placeholder and image rendering logic is correctly implemented, providing a smooth user experience during IPFS URL resolution.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
45-51: Fix rank display condition (checks wrong field).Use rank to decide rendering, not tdh.
const getRankDisplay = () => { if (card.collection === CollectedCollectionType.MEMELAB) { return "N/A"; } else { - return card.tdh ? formatNumberWithCommasOrDash(card.rank ?? 0) : "-"; + return card.rank != null ? formatNumberWithCommasOrDash(card.rank) : "-"; } };
♻️ Duplicate comments (7)
components/nft-transfer/TransferModal.tsx (3)
534-540: Fix close control semantics (button, not SVG) and remove invalid propWrap the icon in a button for keyboard accessibility; FontAwesomeIcon doesn’t accept type="button".
- {(flow === "review" || flow === "success" || flow === "error") && ( - <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> - )} + {(flow === "review" || flow === "success" || flow === "error") && ( + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80" + > + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button> + )}
55-61: Make props readonly to match codebase guidelinesProps must be immutable. Update the signature.
-export default function TransferModal({ - open, - onClose, -}: { - open: boolean; - onClose: (opts?: { completed?: boolean }) => void; -}) { +export default function TransferModal( + { open, onClose }: Readonly<{ + open: boolean; + onClose: (opts?: { completed?: boolean }) => void; + }> +) {
280-287: Guard against missing destination (selectedWallet) at confirmAvoid sending requests without a recipient; show a clear error.
const handleConfirm = useCallback(async () => { - if (!publicClient || !address) { + if (!publicClient || !address) { setErrorMsg("Client not ready. Please reconnect."); setFlow("error"); setRetryable(true); return; } + if (!selectedWallet) { + setErrorMsg("Please select a destination wallet."); + setFlow("error"); + setRetryable(true); + return; + }components/user/collected/UserPageCollected.tsx (1)
242-271: Guard address forcing to avoid redundant router.replace loopsOnly replace when the target differs from the current URL to prevent re-render loops.
if (transferEnabled) { if (!hadForcedRef.current) { previousAddressRef.current = currentParamAddress; } hadForcedRef.current = true; - // Force to connected wallet - updateFields([ - { name: "address", value: connected }, - { name: "page", value: "1" }, - ]); + if (currentParamAddress !== connected) { + updateFields([ + { name: "address", value: connected }, + { name: "page", value: "1" }, + ]); + } } else if (hadForcedRef.current) { const restore = previousAddressRef.current; previousAddressRef.current = null; hadForcedRef.current = false; - updateFields([ - { name: "address", value: restore }, - { name: "page", value: "1" }, - ]); + if (restore !== currentParamAddress) { + updateFields([ + { name: "address", value: restore }, + { name: "page", value: "1" }, + ]); + } }components/user/collected/cards/UserPageCollectedCard.tsx (3)
87-91: Type-safety: coalesce seized_count before formatting.Avoid passing number | null to a formatter expecting number.
- {formatNumberWithCommasOrDash(card.seized_count)}x + {formatNumberWithCommasOrDash(card.seized_count ?? 0)}xAs per coding guidelines
112-129: Checkbox: add onChange, stopPropagation, and align Tailwind prefix.Prevents React controlled-input warning and bubbling; also standardize to tw- classes and use a label for a11y.
- <input - checked={selected} - id={`${card.collection}-${card.token_id}`} - type="checkbox" - className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" - /> + <input + checked={selected} + id={`${card.collection}-${card.token_id}`} + type="checkbox" + className="tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded-sm focus:tw-ring-2 focus:tw-ring-blue-500 dark:tw-focus:tw-ring-blue-600 dark:tw-ring-offset-gray-800 dark:tw-bg-gray-700 dark:tw-border-gray-600" + onChange={onToggle} + onClick={(e) => e.stopPropagation()} + /> {contractType === ContractType.ERC1155 ? ( <> - <span className="tw-text-sm tw-font-medium"> + <label + htmlFor={`${card.collection}-${card.token_id}`} + className="tw-text-sm tw-font-medium" + onClick={(e) => e.stopPropagation()} + > {selected ? `Selected ${ copiesMax === 1 ? `${qtySelected} / ${copiesMax}` : "" }` : copiesMax > 1 ? `Select (up to ${copiesMax})` : "Select"} - </span> + </label> </> ) : ( - <span className="tw-text-sm tw-font-medium"> + <label + htmlFor={`${card.collection}-${card.token_id}`} + className="tw-text-sm tw-font-medium" + onClick={(e) => e.stopPropagation()} + > {selected ? "Selected" : "Select"} - </span> + </label> )}As per coding guidelines
Also applies to: 161-166
53-55: Remove inline TSX comment.TS/TSX files should not contain code comments.
- // shared card bodyAs per coding guidelines
🧹 Nitpick comments (5)
components/nft-transfer/TransferModalPfp.tsx (1)
47-53: Consider adding error handling for Image loading failures.The Next.js
Imagecomponent may fail to load due to network issues, invalid URLs, or CORS problems. Consider adding error handling to gracefully fallback to the placeholder or show an error state.You can add an
onErrorhandler to the Image component:const [imageError, setImageError] = useState(false); // In the render: {(!resolved || imageError) ? ( // placeholder render ) : ( <Image src={resolved} alt={alt ?? ""} width={size} height={size} className="tw-rounded-full tw-object-cover" onError={() => setImageError(true)} /> )}components/nft-transfer/TransferModal.tsx (3)
131-167: Use react-query for recipient search (per project guideline)Replace manual fetch/debounce with react-query (caching, retries, cancelation).
Example pattern (adapt to local QueryKey):
const q = query.trim().toLowerCase(); const { data: searchResults = [], isFetching: isSearching } = useQuery({ queryKey: ["community-members", q], queryFn: async () => q ? await (await fetch(`https://api.6529.io/api/community-members?param=${encodeURIComponent(q)}`)).json() : [], enabled: open && q.length > 0, staleTime: 30_000, gcTime: 5 * 60_000, }); useEffect(() => { if (!open) return; setSelectedProfile(null); setSelectedWallet(null); setResults(searchResults); }, [open, searchResults]);As per coding guidelines
376-383: Remove unnecessary walletClientLocal indirectionUse walletClient directly; simplifies typing and intent.
- const { data: walletClientLocal } = { data: walletClient } as any; - - if (!walletClientLocal) { + if (!walletClient) { setErrorMsg("Wallet not ready. Please reconnect."); setFlow("error"); setRetryable(true); return; }- const hash = await walletClientLocal.writeContract(request); + const hash = await walletClient.writeContract(request);- const hash = await walletClientLocal.writeContract(request); + const hash = await walletClient.writeContract(request);Also applies to: 405-405, 423-423
435-441: Wait for receipts concurrently to reduce total timeParallelize waits for better UX.
- for (const h of hashes) { - await publicClient.waitForTransactionReceipt({ - hash: h.hash as `0x${string}`, - }); - } - - setFlow("success"); + await Promise.all( + hashes.map((h) => + publicClient.waitForTransactionReceipt({ + hash: h.hash as `0x${string}`, + }) + ) + ); + setFlow("success");components/nft-transfer/TransferToggle.tsx (1)
27-47: Optional: add aria-pressed for toggle stateImproves accessibility by conveying pressed/on state.
- <button + <button type="button" + aria-pressed={t.enabled}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
app/[user]/_lib/userTabPageFactory.tsx(3 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferModalPfp.tsx(1 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferState.tsx(1 hunks)components/nft-transfer/TransferToggle.tsx(1 hunks)components/user/collected/UserPageCollected.tsx(9 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)components/user/collected/cards/UserPageCollectedCards.tsx(2 hunks)components/user/utils/level/UserLevel.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app/[user]/_lib/userTabPageFactory.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 propsFollow existing code style and naming conventions
Files:
components/user/collected/cards/UserPageCollectedCard.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxcomponents/nft-transfer/TransferState.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/nft-transfer/TransferPanel.tsxcomponents/user/utils/level/UserLevel.tsxcomponents/nft-transfer/TransferToggle.tsxcomponents/nft-transfer/TransferModalPfp.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
components/user/collected/cards/UserPageCollectedCard.tsxcomponents/user/collected/cards/UserPageCollectedCards.tsxcomponents/nft-transfer/TransferState.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/user/collected/UserPageCollected.tsxcomponents/nft-transfer/TransferPanel.tsxcomponents/user/utils/level/UserLevel.tsxcomponents/nft-transfer/TransferToggle.tsxcomponents/nft-transfer/TransferModalPfp.tsx
🧠 Learnings (1)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (7)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
components/user/collected/cards/UserPageCollectedCards.tsx (3)
components/nft-transfer/TransferState.tsx (2)
useTransfer(164-168)buildTransferKey(170-181)components/user/collected/cards/UserPageCollectedCard.tsx (1)
UserPageCollectedCard(7-197)entities/IProfile.ts (2)
COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE(387-395)COLLECTED_COLLECTION_TYPE_TO_CONTRACT(377-385)
components/nft-transfer/TransferModal.tsx (5)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-60)
components/user/collected/UserPageCollected.tsx (7)
hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/nft-transfer/TransferToggle.tsx (1)
TransferToggle(9-49)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(17-104)components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(11-222)
components/nft-transfer/TransferPanel.tsx (3)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(55-895)
components/nft-transfer/TransferToggle.tsx (2)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)
components/nft-transfer/TransferModalPfp.tsx (1)
components/ipfs/IPFSContext.tsx (1)
resolveIpfsUrl(67-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/nft-transfer/TransferModalPfp.tsx (1)
7-11: LGTM!The level-based color mapping is clear and uses appropriate thresholds for visual differentiation.
components/user/utils/level/UserLevel.tsx (1)
36-39: LGTMNo functional changes; adheres to readonly props and styling conventions.
components/nft-transfer/TransferToggle.tsx (1)
27-47: LGTMToggle logic is sound; integrates with connect flow and TransferState correctly.
components/user/collected/cards/UserPageCollectedCards.tsx (1)
32-37: LGTMTransfer integration and per-card selection/qty wiring look correct.
Also applies to: 42-86
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (8)
components/user/collected/cards/UserPageCollectedCard.tsx (3)
55-55: Remove inline comment (regression from resolved issue)This inline comment violates the repository guideline that TS/TSX files should not contain code comments. This was previously flagged and marked as resolved, but the comment has been reintroduced.
Apply this diff:
- // shared card body const CardBody = (As per coding guidelines
91-91: Type-safety: coalesce seized_count before formatting (regression)
card.seized_countis typed asnumber | null, butformatNumberWithCommasOrDashexpectsnumber. This type mismatch was previously flagged and marked resolved, but the fix appears to have been lost.Apply this diff:
- {formatNumberWithCommasOrDash(card.seized_count)}x + {formatNumberWithCommasOrDash(card.seized_count ?? 0)}x
118-118: Use "tw-" Tailwind prefix on checkbox className (regression)The checkbox's className uses unprefixed Tailwind utilities (e.g.,
w-4,h-4), inconsistent with the rest of the codebase which uses thetw-prefix. This was previously flagged and marked resolved, but the fix appears to have been lost.Apply this diff:
- className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" + className="tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded-sm focus:tw-ring-2 focus:tw-ring-blue-500 dark:focus:tw-ring-blue-600 dark:tw-ring-offset-gray-800 dark:tw-bg-gray-700 dark:tw-border-gray-600"components/nft-transfer/TransferPanel.tsx (2)
34-42: Remove inline comments from TSXTSX must be comment-free per repo rules. Delete or move them to surrounding TS code/doc.
As per coding guidelines
Also applies to: 68-76, 71-81, 211-213
102-105: Replace invalid Tailwind class "tw-border-1" with "tw-border""tw-border-1" isn’t a default Tailwind class.
- className="tw-text-sm tw-rounded-lg tw-bg-white tw-text-black tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-text-sm tw-rounded-lg tw-bg-white tw-text-black tw-py-1 tw-border tw-border-solid tw-border-[#444]"> ... - className="tw-flex-1 tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/20 tw-text-white tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-flex-1 tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/20 tw-text-white tw-py-1 tw-border tw-border-solid tw-border-[#444]"> ... - className="tw-flex-1 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-flex-1 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border tw-border-solid tw-border-[#444]">As per coding guidelines
Also applies to: 198-205
components/nft-transfer/TransferModal.tsx (3)
56-62: Make props readonlyApply readonly props per repo guideline.
-export default function TransferModal({ - open, - onClose, -}: { - open: boolean; - onClose: (opts?: { completed?: boolean }) => void; -}) { +export default function TransferModal( + { open, onClose }: Readonly<{ + open: boolean; + onClose: (opts?: { completed?: boolean }) => void; + }> +) {As per coding guidelines
566-573: Fix close control semantics (wrap icon in a button, remove invalid prop)FontAwesomeIcon doesn’t accept type="button" and isn’t focusable. Wrap it in a button.
- {(flow === "review" || flow === "success" || flow === "error") && ( - <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> - )} + {(flow === "review" || flow === "success" || flow === "error") && ( + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80" + > + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button> + )}
288-294: Guard against missing selectedWallet in confirm pathAdd a runtime check to prevent sending with null destination.
- const handleConfirm = useCallback(async () => { - if (!publicClient || !address) { - setErrorMsg("Client not ready. Please reconnect."); + const handleConfirm = useCallback(async () => { + if (!publicClient || !address || !selectedWallet) { + setErrorMsg(!selectedWallet ? "Please select a destination wallet." : "Client not ready. Please reconnect."); setFlow("error"); setRetryable(true); return; }
🧹 Nitpick comments (18)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
123-130: Clean up trailing space in selection textWhen
copiesMax > 1and the item is selected, the text renders as"Selected "with a trailing space because the template literal embeds an empty string. Consider removing the space or restructuring the conditional for cleaner output.Apply this diff:
<span className="tw-text-sm tw-font-medium"> - {selected - ? `Selected ${ - copiesMax === 1 ? `${qtySelected} / ${copiesMax}` : "" - }` - : copiesMax > 1 - ? `Select (up to ${copiesMax})` - : "Select"} + {selected ? ( + copiesMax === 1 ? `Selected ${qtySelected} / ${copiesMax}` : "Selected" + ) : ( + copiesMax > 1 ? `Select (up to ${copiesMax})` : "Select" + )} </span>__tests__/components/nft-transfer/TransferModalPfp.test.tsx (2)
1-9: Mock next/image to avoid Jest environment quirksWithout mocking next/image, tests can be flaky or fail under jsdom. Add a lightweight mock here.
Apply:
import { render, screen, waitFor } from "@testing-library/react"; import TransferModalPfp from "@/components/nft-transfer/TransferModalPfp"; const mockResolveIpfsUrl = jest.fn(); jest.mock("@/components/ipfs/IPFSContext", () => ({ resolveIpfsUrl: (...args: unknown[]) => mockResolveIpfsUrl(...args), })); +jest.mock("next/image", () => ({ + __esModule: true, + default: ({ alt = "", src, ...rest }: any) => <img src={src} alt={alt} {...rest} />, +}));
23-31: Also assert resolution call for stronger testValidate the resolver is invoked with the provided IPFS URL.
it("loads and displays the resolved image", async () => { mockResolveIpfsUrl.mockResolvedValue("https://cdn.test/pfp.png"); render(<TransferModalPfp level={45} src="ipfs://hash" alt="Profile" />); + expect(mockResolveIpfsUrl).toHaveBeenCalledWith("ipfs://hash"); await waitFor(() => expect(screen.getByRole("img", { name: "Profile" })).toBeInTheDocument() ); });components/the-memes/MemePageYourCards.tsx (1)
226-244: RedundantcontractTypeprop; ensure contract mapping matches keyTransferSingle derives
contractTypefromcollectionTypeinternally and doesn’t use the passedcontractType. Keeping it may confuse future readers. Consider removing this prop across component definition and all call sites in a follow-up.Also, since the selection key uses the
contractprop while the selected item’scontractuses the mapping, please verify MEMES mapping equals MEMES_CONTRACT to avoid key/contract divergence.components/memelab/MemeLabPage.tsx (1)
685-701: AligncontractTypeusage and verify mapping equals MEMES_CONTRACTAs with the other page, TransferSingle computes
contractTypefromcollectionType. Passing it is redundant. Consider simplifying the prop surface later. Also confirm the MEMES mapping address equals MEMES_CONTRACT so the key (built fromcontract) and the stored item contract remain consistent.__tests__/components/nft-transfer/TransferPanel.test.tsx (1)
1-1: Prefer user-event over fireEventUse
@testing-library/user-eventto better simulate real user interactions (clicks respect disabled state).-import { fireEvent, render, screen } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event";And replace
fireEvent.click(...)withawait userEvent.click(...)inside async tests.__tests__/components/nft-transfer/TransferSingle.test.tsx (1)
147-159: Optional: prefer user-event for clicksUse
user-eventfor better fidelity.-import { cleanup, fireEvent, render, screen } from "@testing-library/react"; +import { cleanup, render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; ... - fireEvent.click(minus); - fireEvent.click(plus); + await userEvent.click(minus); + await userEvent.click(plus);__tests__/components/nft-transfer/TransferToggle.test.tsx (1)
1-1: Prefer userEvent for realistic interactions in testsAdopt @testing-library/user-event for clicks to align with testing best practices and repo guidelines.
- import { fireEvent, render, screen } from "@testing-library/react"; + import { render, screen } from "@testing-library/react"; + import userEvent from "@testing-library/user-event"; ... - it("requests connection before enabling transfer", () => { + it("requests connection before enabling transfer", async () => { + const user = userEvent.setup(); ... - fireEvent.click(screen.getByRole("button", { name: /transfer/i })); + await user.click(screen.getByRole("button", { name: /transfer/i })); ... - it("disables transfer and clears selections when toggled off", () => { + it("disables transfer and clears selections when toggled off", async () => { + const user = userEvent.setup(); ... - fireEvent.click(screen.getByRole("button", { name: /exit transfer/i })); + await user.click(screen.getByRole("button", { name: /exit transfer/i }));As per coding guidelines
Also applies to: 40-43, 67-70
__tests__/components/nft-transfer/TransferModal.test.tsx (2)
18-22: Fix mock shape for default exportsReturn an object with __esModule and default to avoid ESM interop issues in Jest.
-jest.mock("@/components/nft-transfer/TransferModalPfp", () => { - const MockTransferModalPfp = () => <div data-testid="pfp" />; - MockTransferModalPfp.displayName = "MockTransferModalPfp"; - return MockTransferModalPfp; -}); +jest.mock("@/components/nft-transfer/TransferModalPfp", () => ({ + __esModule: true, + default: () => <div data-testid="pfp" />, +})); ... -jest.mock("@/components/distribution-plan-tool/common/CircleLoader", () => { - const MockCircleLoader = () => <div data-testid="loader" />; - MockCircleLoader.displayName = "MockCircleLoader"; - return MockCircleLoader; -}); +jest.mock("@/components/distribution-plan-tool/common/CircleLoader", () => ({ + __esModule: true, + default: () => <div data-testid="loader" />, +}));If your Jest config already handles synthetic default imports, confirm tests pass as-is; otherwise apply the change. Based on learnings
Also applies to: 23-27
1-7: Use userEvent for typing and clicksSwitch to @testing-library/user-event for input and button interactions.
-import { - act, - fireEvent, - render, - screen, - waitFor, -} from "@testing-library/react"; +import { act, render, screen, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; ... - async function selectRecipientFlow() { + async function selectRecipientFlow() { + const user = userEvent.setup(); ... - const input = screen.getByPlaceholderText(/search by handle/i); - fireEvent.change(input, { target: { value: "rec" } }); + const input = screen.getByPlaceholderText(/search by handle/i); + await user.type(input, "rec"); ... - fireEvent.click(screen.getByRole("button", { name: /recipient/i })); - fireEvent.click( + await user.click(screen.getByRole("button", { name: /recipient/i })); + await user.click( screen.getByRole("button", { name: /recipient\s+0xrecipient/i }) ); ... - fireEvent.click(screen.getByRole("button", { name: /^transfer$/i })); + const user = userEvent.setup(); + await user.click(screen.getByRole("button", { name: /^transfer$/i })); ... - fireEvent.click(screen.getByRole("button", { name: /^transfer$/i })); + const user = userEvent.setup(); + await user.click(screen.getByRole("button", { name: /^transfer$/i }));As per coding guidelines
Also applies to: 147-149, 157-161, 188-197, 204-210
components/nft-transfer/TransferPanel.tsx (1)
151-169: Use semantic buttons for +/- controlsWrap icons in buttons for keyboard/a11y; keep icons inside.
- <FontAwesomeIcon - icon={faMinusCircle} - onClick={() => t.decQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty <= 1 ? "#60606C" : "#fff"} - aria-disabled={qty <= 1} - /> + <button + type="button" + onClick={() => t.decQty(it.key)} + disabled={qty <= 1} + className="tw-inline-flex tw-items-center disabled:tw-opacity-60" + aria-label="Decrease quantity"> + <FontAwesomeIcon + icon={faMinusCircle} + className="tw-size-6" + color={qty <= 1 ? "#60606C" : "#fff"} + /> + </button> ... - <FontAwesomeIcon - icon={faPlusCircle} - onClick={() => t.incQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty >= max ? "#60606C" : "#fff"} - aria-disabled={qty >= max} - /> + <button + type="button" + onClick={() => t.incQty(it.key)} + disabled={qty >= max} + className="tw-inline-flex tw-items-center disabled:tw-opacity-60" + aria-label="Increase quantity"> + <FontAwesomeIcon + icon={faPlusCircle} + className="tw-size-6" + color={qty >= max ? "#60606C" : "#fff"} + /> + </button>components/nft-transfer/TransferSingle.tsx (3)
107-111: Replace invalid Tailwind class "tw-border-1" with "tw-border"Use Tailwind’s tw-border for 1px borders.
- className="tw-w-full tw-py-2 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border-1 tw-border-solid tw-border-[#444] tw-text-lg tw-font-semibold" + className="tw-w-full tw-py-2 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border tw-border-solid tw-border-[#444] tw-text-lg tw-font-semibold"As per coding guidelines
20-36: Align contract/contractType sources or remove unused propsProps include contract/contractType, but selection uses mappings from collectionType instead, while the key uses the contract prop. This can confuse readers and produce odd labels from key.
Options:
- Use the contract/contractType props in t.select, or
- Drop those props and derive both from collectionType consistently.
Example applying props in select:
- t.select({ - key, - contract: COLLECTED_COLLECTION_TYPE_TO_CONTRACT[collectionType], - contractType: COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE[ - collectionType - ] as ContractType, + t.select({ + key, + contract, + contractType, tokenId, max, thumbUrl, title, });Also applies to: 48-60
80-100: Use semantic buttons for +/- controlsMirror the a11y pattern used in the panel by wrapping icons in buttons.
components/nft-transfer/TransferModal.tsx (4)
727-735: Replace invalid Tailwind class "tw-border-1" with "tw-border"Use Tailwind’s tw-border for 1px borders.
- className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]" + className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border tw-border-solid tw-border-[#444]" ... - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]"> ... - className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> + className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed">As per coding guidelines
Also applies to: 879-887
540-575: Remove inline comments from TSXDelete JSX comments to comply with no-comments-in-TSX rule. Move notes to surrounding TS code or doc if needed.
As per coding guidelines
Also applies to: 577-581, 635-643, 801-805, 872-920
139-175: Prefer react-query for search instead of local fetch/debounceReplace in-component fetch with a useQuery keyed by the query string (enabled when q length > 0). Use a debounced state or a custom hook to debounce q.
As per coding guidelines
384-391: Simplify wallet client handlingYou already have walletClient from useWalletClient(); avoid re-wrapping to extract data again.
- const { data: walletClientLocal } = { data: walletClient } as any; - - if (!walletClientLocal) { + const walletClientLocal = walletClient; + if (!walletClientLocal) { setErrorMsg("Wallet not ready. Please reconnect."); setFlow("error"); setRetryable(true); return; }Also applies to: 413-417, 431-436
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferModalPfp.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferPanel.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferState.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferToggle.test.tsx(1 hunks)components/memelab/MemeLabPage.tsx(3 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/the-memes/MemePageYourCards.tsx(2 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)styles/Home.module.scss(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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 propsFollow existing code style and naming conventions
Files:
__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsxcomponents/memelab/MemeLabPage.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/nft-transfer/TransferPanel.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsxcomponents/the-memes/MemePageYourCards.tsx__tests__/components/nft-transfer/TransferState.test.tsxcomponents/nft-transfer/TransferSingle.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsxcomponents/memelab/MemeLabPage.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/nft-transfer/TransferPanel.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsxcomponents/the-memes/MemePageYourCards.tsx__tests__/components/nft-transfer/TransferState.test.tsxcomponents/nft-transfer/TransferSingle.tsx__tests__/components/nft-transfer/TransferModal.test.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/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx__tests__/components/nft-transfer/TransferModal.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/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
{**/__tests__/**,**/*.test.{ts,tsx}}: If coverage on a modified file is below 80%, add meaningful tests to raise it to at least 80%
Mock external dependencies and APIs in tests
Files:
__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
**/__tests__/**
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directories when organizing standalone test suites
Files:
__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
**/*.test.tsx
📄 CodeRabbit inference engine (AGENTS.md)
When co-locating tests with components, name them
ComponentName.test.tsx
Files:
__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
🧠 Learnings (1)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (12)
__tests__/components/nft-transfer/TransferToggle.test.tsx (1)
components/nft-transfer/TransferToggle.tsx (1)
TransferToggle(9-49)
__tests__/components/nft-transfer/TransferModalPfp.test.tsx (1)
components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-60)
components/memelab/MemeLabPage.tsx (3)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)constants.ts (1)
MEMES_CONTRACT(5-5)
components/nft-transfer/TransferModal.tsx (5)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-60)
__tests__/components/nft-transfer/TransferPanel.test.tsx (1)
components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(16-224)
__tests__/components/nft-transfer/TransferSingle.test.tsx (2)
components/nft-transfer/TransferState.tsx (2)
buildTransferKey(170-181)useTransfer(164-168)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)
components/nft-transfer/TransferPanel.tsx (3)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(56-924)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
components/the-memes/MemePageYourCards.tsx (3)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)constants.ts (1)
MEMES_CONTRACT(5-5)
__tests__/components/nft-transfer/TransferState.test.tsx (1)
components/nft-transfer/TransferState.tsx (3)
useTransfer(164-168)TransferProvider(46-162)buildTransferKey(170-181)
components/nft-transfer/TransferSingle.tsx (2)
components/nft-transfer/TransferState.tsx (2)
useTransfer(164-168)buildTransferKey(170-181)entities/IProfile.ts (2)
COLLECTED_COLLECTION_TYPE_TO_CONTRACT(377-385)COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE(387-395)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(56-924)
⏰ 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 (2)
styles/Home.module.scss (1)
161-173: New shadow container styling looks solid.Matches existing theme variables and gives us a reusable dark card treatment. Nicely done.
__tests__/components/nft-transfer/TransferState.test.tsx (1)
15-22: Good coverage of initial stateAssertions match provider defaults and totals. Looks solid.
There was a problem hiding this comment.
Actionable comments posted: 10
♻️ Duplicate comments (5)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
91-91: Coalesce seized_count to ensure type safety.
card.seized_countisnumber | nullbutformatNumberWithCommasOrDashexpectsnumber. Pass a coalesced value to maintain type safety.Apply this diff:
- {formatNumberWithCommasOrDash(card.seized_count)}x + {formatNumberWithCommasOrDash(card.seized_count ?? 0)}x
114-120: Apply tw- prefix to checkbox Tailwind classes.The checkbox uses unprefixed Tailwind utilities (
w-4 h-4 text-blue-600 bg-gray-100etc.), which is inconsistent with the repository's Tailwind configuration requiring thetw-prefix.Apply this diff:
<input checked={selected} id={`${card.collection}-${card.token_id}`} type="checkbox" - className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" + className="tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded-sm focus:tw-ring-blue-500 dark:focus:tw-ring-blue-600 dark:tw-ring-offset-gray-800 focus:tw-ring-2 dark:tw-bg-gray-700 dark:tw-border-gray-600" readOnly />components/nft-transfer/TransferPanel.tsx (1)
34-42: Remove inline comments from TS/TSX per repo rules.No comments allowed in TS/TSX files. Delete these comment lines (and any others), or move explanations to variable names or separate docs.
As per coding guidelines
Also applies to: 57-61, 68-76, 78-82, 211-211
components/nft-transfer/TransferModal.tsx (2)
58-64: Make props readonly.Props must be readonly per repo rules.
-export default function TransferModal({ - open, - onClose, -}: { - open: boolean; - onClose: (opts?: { completed?: boolean }) => void; -}) { +export default function TransferModal( + { open, onClose }: Readonly<{ + open: boolean; + onClose: (opts?: { completed?: boolean }) => void; + }> +) {As per coding guidelines
580-585: Fix close control semantics (wrap icon in a button).FontAwesomeIcon isn't a button and doesn't accept type. Wrap in a semantic button.
- <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80" + > + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button>
🧹 Nitpick comments (6)
components/the-memes/MemePageYourCards.tsx (1)
234-239: Optional: Remove redundant optional chaining.After the guard at line 226,
props.nftis guaranteed to exist and have anid. Optional chaining on lines 234, 237, and 239 is redundant.- tokenId={props.nft?.id} + tokenId={props.nft.id} max={props.nftBalance} title={ - props.nft?.name ?? `The Memes #${props.nft?.id}` + props.nft.name ?? `The Memes #${props.nft.id}` } - thumbUrl={props.nft?.thumbnail} + thumbUrl={props.nft.thumbnail}components/memelab/MemeLabPage.tsx (1)
685-701: Optional: Remove redundant optional chaining.Line 693 uses
nft?.idbut the outer condition on line 685 already ensuresnft?.idis truthy, making the optional chaining redundant. While defensive programming is acceptable, you can simplify:{nftBalance > 0 && nft?.id && ( <Row className="pt-5"> <Col> <TransferProvider> <TransferSingle collectionType={CollectedCollectionType.MEMES} contractType={ContractType.ERC1155} contract={MEMES_CONTRACT} - tokenId={nft?.id} + tokenId={nft.id} max={nftBalance} title={nft?.name ?? `The Memes #${nft?.id}`} thumbUrl={nft?.thumbnail} /> </TransferProvider> </Col> </Row> )}__tests__/components/nft-transfer/TransferModal.test.tsx (1)
127-161: Ensure timer cleanup in selectRecipientFlow helper.The
selectRecipientFlowhelper usesjest.useFakeTimers()(line 128) andjest.useRealTimers()(line 155). If an assertion fails between these calls, the test will exit without restoring real timers, potentially affecting subsequent tests.While
afterEach(line 115) includes cleanup, it's safer to use a try-finally block in the helper.Apply this diff:
async function selectRecipientFlow() { jest.useFakeTimers(); + try { + (global.fetch as jest.Mock).mockResolvedValue({ + ok: true, + json: jest.fn().mockResolvedValue([ + { + profile_id: "1", + handle: "recipient", + display: "Recipient", + wallet: "0xrecipient", + level: 10, + tdh: 100, + pfp: null, + }, + ]), + }); - (global.fetch as jest.Mock).mockResolvedValue({ - ok: true, - json: jest.fn().mockResolvedValue([ - { - profile_id: "1", - handle: "recipient", - display: "Recipient", - wallet: "0xrecipient", - level: 10, - tdh: 100, - pfp: null, - }, - ]), - }); - - openModal(); - - const input = screen.getByPlaceholderText(/search by handle/i); - fireEvent.change(input, { target: { value: "rec" } }); - - await act(async () => { - jest.advanceTimersByTime(400); - }); - - await waitFor(() => expect(global.fetch).toHaveBeenCalled()); - jest.useRealTimers(); - - fireEvent.click(screen.getByRole("button", { name: /recipient/i })); - fireEvent.click( - screen.getByRole("button", { name: /recipient\s+0xrecipient/i }) - ); + openModal(); + + const input = screen.getByPlaceholderText(/search by handle/i); + fireEvent.change(input, { target: { value: "rec" } }); + + await act(async () => { + jest.advanceTimersByTime(400); + }); + + await waitFor(() => expect(global.fetch).toHaveBeenCalled()); + + fireEvent.click(screen.getByRole("button", { name: /recipient/i })); + fireEvent.click( + screen.getByRole("button", { name: /recipient\s+0xrecipient/i }) + ); + } finally { + jest.useRealTimers(); + } }components/nft-transfer/TransferPanel.tsx (1)
151-170: Make plus/minus controls keyboard-accessible.Wrap FontAwesome icons in s with aria-label and disabled to support keyboard/a11y.
- <FontAwesomeIcon - icon={faMinusCircle} - onClick={() => t.decQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty <= 1 ? "#60606C" : "#fff"} - aria-disabled={qty <= 1} - /> + <button + type="button" + onClick={() => t.decQty(it.key)} + aria-label="Decrease quantity" + disabled={qty <= 1} + className="tw-inline-flex tw-items-center tw-justify-center disabled:tw-opacity-50" + > + <FontAwesomeIcon + icon={faMinusCircle} + className="tw-size-6" + color={qty <= 1 ? "#60606C" : "#fff"} + /> + </button> ... - <FontAwesomeIcon - icon={faPlusCircle} - onClick={() => t.incQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty >= max ? "#60606C" : "#fff"} - aria-disabled={qty >= max} - /> + <button + type="button" + onClick={() => t.incQty(it.key)} + aria-label="Increase quantity" + disabled={qty >= max} + className="tw-inline-flex tw-items-center tw-justify-center disabled:tw-opacity-50" + > + <FontAwesomeIcon + icon={faPlusCircle} + className="tw-size-6" + color={qty >= max ? "#60606C" : "#fff"} + /> + </button>components/nft-transfer/TransferSingle.tsx (1)
80-100: Make plus/minus controls keyboard-accessible.Wrap icons in buttons with aria-label/disabled.
- <FontAwesomeIcon - icon={faMinusCircle} - onClick={() => t.decQty(key)} - className="tw-size-6 tw-cursor-pointer" - color={selectedQty <= 1 ? "#60606C" : "#fff"} - aria-disabled={selectedQty <= 1} - data-testid="transfer-single-minus" - /> + <button + type="button" + onClick={() => t.decQty(key)} + aria-label="Decrease quantity" + disabled={selectedQty <= 1} + className="tw-inline-flex tw-items-center tw-justify-center disabled:tw-opacity-50" + data-testid="transfer-single-minus" + > + <FontAwesomeIcon + icon={faMinusCircle} + className="tw-size-6" + color={selectedQty <= 1 ? "#60606C" : "#fff"} + /> + </button> ... - <FontAwesomeIcon - icon={faPlusCircle} - onClick={() => t.incQty(key)} - className="tw-size-6 tw-cursor-pointer" - color={selectedQty >= max ? "#60606C" : "#fff"} - aria-disabled={selectedQty >= max} - data-testid="transfer-single-plus" - /> + <button + type="button" + onClick={() => t.incQty(key)} + aria-label="Increase quantity" + disabled={selectedQty >= max} + className="tw-inline-flex tw-items-center tw-justify-center disabled:tw-opacity-50" + data-testid="transfer-single-plus" + > + <FontAwesomeIcon + icon={faPlusCircle} + className="tw-size-6" + color={selectedQty >= max ? "#60606C" : "#fff"} + /> + </button>components/nft-transfer/TransferModal.tsx (1)
148-185: Use react-query for search instead of manual fetch/debounce.Replace the custom debounce/AbortController with a useQuery keyed by the query, with enabled: open && trimmedQuery.length >= MIN_SEARCH_LENGTH. Improves consistency and caching.
As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferModalPfp.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferPanel.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferState.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferToggle.test.tsx(1 hunks)components/memelab/MemeLabPage.tsx(3 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferModalPfp.tsx(1 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/the-memes/MemePageYourCards.tsx(2 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)styles/Home.module.scss(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- styles/Home.module.scss
🚧 Files skipped from review as they are similar to previous changes (1)
- components/nft-transfer/TransferModalPfp.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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 propsFollow existing code style and naming conventions
Files:
components/nft-transfer/TransferPanel.tsxcomponents/the-memes/MemePageYourCards.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsxcomponents/memelab/MemeLabPage.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsxcomponents/nft-transfer/TransferSingle.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsxcomponents/nft-transfer/TransferModal.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
components/nft-transfer/TransferPanel.tsxcomponents/the-memes/MemePageYourCards.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsx__tests__/components/nft-transfer/TransferModalPfp.test.tsxcomponents/memelab/MemeLabPage.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsxcomponents/nft-transfer/TransferSingle.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsxcomponents/nft-transfer/TransferModal.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/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.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/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
{**/__tests__/**,**/*.test.{ts,tsx}}: If coverage on a modified file is below 80%, add meaningful tests to raise it to at least 80%
Mock external dependencies and APIs in tests
Files:
__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx
**/__tests__/**
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directories when organizing standalone test suites
Files:
__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx
**/*.test.tsx
📄 CodeRabbit inference engine (AGENTS.md)
When co-locating tests with components, name them
ComponentName.test.tsx
Files:
__tests__/components/nft-transfer/TransferModalPfp.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/nft-transfer/TransferToggle.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferState.test.tsx
🧠 Learnings (1)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (12)
components/nft-transfer/TransferPanel.tsx (3)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-941)
components/the-memes/MemePageYourCards.tsx (3)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)constants.ts (1)
MEMES_CONTRACT(5-5)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
__tests__/components/nft-transfer/TransferModalPfp.test.tsx (1)
components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
components/memelab/MemeLabPage.tsx (3)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)constants.ts (1)
MEMES_CONTRACT(5-5)
__tests__/components/nft-transfer/TransferPanel.test.tsx (1)
components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(16-224)
__tests__/components/nft-transfer/TransferSingle.test.tsx (2)
components/nft-transfer/TransferState.tsx (2)
buildTransferKey(170-181)useTransfer(164-168)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(20-115)
__tests__/components/nft-transfer/TransferToggle.test.tsx (1)
components/nft-transfer/TransferToggle.tsx (1)
TransferToggle(9-49)
components/nft-transfer/TransferSingle.tsx (3)
components/nft-transfer/TransferState.tsx (2)
useTransfer(164-168)buildTransferKey(170-181)entities/IProfile.ts (2)
COLLECTED_COLLECTION_TYPE_TO_CONTRACT(377-385)COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE(387-395)components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-941)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-941)
__tests__/components/nft-transfer/TransferState.test.tsx (1)
components/nft-transfer/TransferState.tsx (3)
useTransfer(164-168)TransferProvider(46-162)buildTransferKey(170-181)
components/nft-transfer/TransferModal.tsx (6)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
⏰ 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 (2)
components/the-memes/MemePageYourCards.tsx (1)
226-226: Use explicit existence check fornft.id
props.nft?.idis falsy for0, preventing valid token IDs. Replace with an explicit check and confirm ifid = 0is ever used:- {props.nftBalance > 0 && props.myOwner && props.nft?.id && ( + {props.nftBalance > 0 && props.myOwner && props.nft?.id !== undefined && (components/nft-transfer/TransferModal.tsx (1)
415-452: No chain propagation changes required publicClient and walletClient are instantiated with a chain at creation, so simulateContract/writeContract inherit the correct chain.
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
__tests__/components/user/collected/UserPageCollected.test.tsx (1)
77-80: Use wallets array in mockProfile to match ApiIdentity
In tests/components/user/collected/UserPageCollected.test.tsx replace the singlewalletfield with awalletsarray—e.g.:const mockProfile = { handle: "testuser", wallets: [{ wallet: "0x123" }], } as ApiIdentity;This ensures the mock aligns with the interface and satisfies the
profile.wallets?.some(…)check.
♻️ Duplicate comments (7)
components/nft-transfer/TransferModal.tsx (5)
58-64: Make props readonly to match project rules
Props must be immutable. Update signature as below.As per coding guidelines
-export default function TransferModal({ - open, - onClose, -}: { - open: boolean; - onClose: (opts?: { completed?: boolean }) => void; -}) { +export default function TransferModal( + { open, onClose }: Readonly<{ + open: boolean; + onClose: (opts?: { completed?: boolean }) => void; + }> +) {
1-926: Remove comments from TSX per project rules
TS/TSX must be comment-free. Remove inline comments and JSX comments (e.g., lines 23-26, 97-101, 206-216, 217-223, 538-573, 575-586, 633-641, 741-797, 874-922).As per coding guidelines
565-571: Fix close control semantics (wrap icon in a button)
FontAwesomeIcon isn’t a button and type="button" is invalid on it. Wrap it for a11y.- {(flow === "review" || flow === "success" || flow === "error") && ( - <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> - )} + {(flow === "review" || flow === "success" || flow === "error") && ( + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80" + > + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button> + )}
729-736: Replace invalid Tailwind class "tw-border-1" with "tw-border"
tw-border-1 isn’t valid; use tw-border (or tw-border-[1px]).- className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]" + className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border tw-border-solid tw-border-[#444]" @@ - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]"> @@ - className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> + className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> @@ - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]">Also applies to: 879-891, 900-906
670-694: Avoid potential null React keys in results list
profile_id can be null. Use a stable non-null fallback.- {results.map((r: CommunityMemberMinimal) => ( + {results.map((r: CommunityMemberMinimal) => ( <button - key={r.profile_id} + key={r.profile_id ?? r.wallet}components/nft-transfer/TransferPanel.tsx (2)
34-41: Remove comments from TSX
Delete inline and JSX comments to comply.As per coding guidelines
Also applies to: 55-62, 68-76, 213-213
102-105: Replace invalid Tailwind class "tw-border-1" with "tw-border"
Fix on Clear/Cancel/Continue buttons.- className="tw-text-sm tw-rounded-lg tw-bg-white tw-text-black tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-text-sm tw-rounded-lg tw-bg-white tw-text-black tw-py-1 tw-border tw-border-solid tw-border-[#444]"> @@ - className="tw-flex-1 tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/20 tw-text-white tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-flex-1 tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/20 tw-text-white tw-py-1 tw-border tw-border-solid tw-border-[#444]"> @@ - className="tw-flex-1 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-flex-1 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border tw-border-solid tw-border-[#444]">Also applies to: 200-208
🧹 Nitpick comments (8)
__tests__/components/memelab/MemeLabPage.test.tsx (1)
365-377: Test setup correctly provides Wagmi context for transfer UI.The mock Wagmi configuration and provider wrapper are appropriate for testing the "your cards" tab, which conditionally renders the transfer UI based on NFT balance and tab focus.
Consider moving
WagmiProviderto therenderWithQueryClientwrapper function for consistency across all tests:const renderWithQueryClient = (component: React.ReactElement) => { const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, }, }, }); + const mockWagmiConfig = createConfig({ + chains: [mainnet], + transports: { + [mainnet.id]: http(), + }, + }); return render( - <QueryClientProvider client={queryClient}>{component}</QueryClientProvider> + <QueryClientProvider client={queryClient}> + <WagmiProvider config={mockWagmiConfig}> + {component} + </WagmiProvider> + </QueryClientProvider> ); };Then simplify the test call:
await act(async () => { - renderWithQueryClient( - <WagmiProvider config={mockWagmiConfig}> - <MemeLabPageComponent nftId="1" /> - </WagmiProvider> - ); + renderWithQueryClient(<MemeLabPageComponent nftId="1" />); });This ensures all tests have Wagmi context available, making the test suite more robust if component requirements change or new tests exercise the transfer UI code paths.
__tests__/components/the-memes/MemePageYourCards.test.tsx (2)
11-39: Consider using Partial types instead ofas any.While
as anyis acceptable in tests, usingPartial<NFT>,Partial<ConsolidatedTDH>, andPartial<Transaction[]>would provide better type safety and catch potential type mismatches.Apply this diff to improve type safety:
-const mockNFT = { +const mockNFT: Partial<NFT> = { id: 123, name: "Test Meme", artist: "Test Artist", -} as any; +}; -const mockConsolidatedTDH = { +const mockConsolidatedTDH: Partial<ConsolidatedTDH> = { wallets: ["0x123"], balance: 5, tdh: 1000, dense_rank_balance: 10, -} as any; +}; -const mockTransactions = [ +const mockTransactions: Partial<Transaction>[] = [ { transaction_date: new Date("2023-01-01"), from_address: "0x0000000000000000000000000000000000000000", to_address: "0x456", value: 0, token_count: 1, }, { transaction_date: new Date("2023-01-02"), from_address: "0x789", to_address: "0x456", value: 1.5, token_count: 2, }, -] as any[]; +];
56-208: Consider adding tests for additional transaction categories.The test suite has good coverage of core scenarios, and the selective use of
renderWithProvidersis correct (only whenTransferSinglewould render). However, consider adding tests for:
- Transferred in cards (non-zero value transfers from other addresses)
- Transferred out cards (transfers from user wallets)
- Sold cards (positive value transfers from user wallets)
- Edge cases with multiple token counts in transactions
Example additional test:
it("should categorize transferred in cards", () => { const txWithTransferIn = [ { transaction_date: new Date("2023-01-01"), from_address: "0x789", to_address: "0x456", value: 0, token_count: 1, }, ]; renderWithQueryAndWagmiProviders( <MemePageYourCardsRightMenu show={true} transactions={txWithTransferIn} wallets={["0x456"]} nft={mockNFT} nftBalance={1} myOwner={mockConsolidatedTDH} myTDH={undefined} myRank={undefined} /> ); expect(screen.getByText("1 card transferred in")).toBeInTheDocument(); });__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx (1)
22-34: Reset shared mock state between tests to avoid leakagepaginationProps is module-scoped and retains values across tests. Reset it in beforeEach to keep tests isolated.
+beforeEach(() => { + for (const k of Object.keys(paginationProps)) delete (paginationProps as any)[k]; +});components/nft-transfer/TransferModal.tsx (1)
304-311: Remove unused variable
wroteTransaction is set but unused.- let wroteTransaction = false; try { @@ - wroteTransaction = true; @@ - wroteTransaction = true;__tests__/components/nft-transfer/TransferModal.test.tsx (1)
175-209: Strengthen assertions to catch ERC721 vs ERC1155 mixups
Also assert functionName/ABI per call to ensure correct contract paths.- await waitFor(() => expect(simulateContract).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(simulateContract).toHaveBeenCalledTimes(2)); + const calls = (simulateContract as jest.Mock).mock.calls; + expect(calls.some(([, , args]) => (args ?? calls[0])[0]?.functionName === "safeBatchTransferFrom")).toBe(true); + expect(calls.some(([, , args]) => (args ?? calls[0])[0]?.functionName === "safeTransferFrom")).toBe(true);components/nft-transfer/TransferPanel.tsx (2)
151-171: Use buttons for +/- controls for keyboard a11y
Wrap icons in with disabled state.- <FontAwesomeIcon - icon={faMinusCircle} - onClick={() => t.decQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty <= 1 ? "#60606C" : "#fff"} - aria-disabled={qty <= 1} - data-testid="transfer-panel-minus" - /> + <button + type="button" + onClick={() => t.decQty(it.key)} + disabled={qty <= 1} + aria-label="Decrease quantity" + className="tw-text-white disabled:tw-text-[#60606C]" + data-testid="transfer-panel-minus" + > + <FontAwesomeIcon icon={faMinusCircle} className="tw-size-6" /> + </button> @@ - <FontAwesomeIcon - icon={faPlusCircle} - onClick={() => t.incQty(it.key)} - className="tw-size-6 tw-cursor-pointer" - color={qty >= max ? "#60606C" : "#fff"} - aria-disabled={qty >= max} - data-testid="transfer-panel-plus" - /> + <button + type="button" + onClick={() => t.incQty(it.key)} + disabled={qty >= max} + aria-label="Increase quantity" + className="tw-text-white disabled:tw-text-[#60606C]" + data-testid="transfer-panel-plus" + > + <FontAwesomeIcon icon={faPlusCircle} className="tw-size-6" /> + </button>
174-181: Use FontAwesome for the remove icon
Replace × with FontAwesome for consistency and a11y.-import { - faAnglesDown, - faAnglesUp, - faMinusCircle, - faPlusCircle, -} from "@fortawesome/free-solid-svg-icons"; +import { + faAnglesDown, + faAnglesUp, + faMinusCircle, + faPlusCircle, + faXmark, +} from "@fortawesome/free-solid-svg-icons"; @@ - <button + <button type="button" - className="tw-inline-flex tw-items-center tw-justify-center tw-h-6 tw-w-6 tw-rounded-full tw-bg-[#ef4444] tw-font-medium tw-text-white hover:tw-bg-[#d92b2b] tw-text-lg tw-p-0 tw-border-0" + className="tw-inline-flex tw-items-center tw-justify-center tw-h-6 tw-w-6 tw-rounded-full tw-bg-[#ef4444] tw-text-white hover:tw-bg-[#d92b2b] tw-p-0 tw-border-0" onClick={() => t.unselect(it.key)} aria-label="Remove"> - × + <FontAwesomeIcon icon={faXmark} /> </button>Also applies to: 5-9
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
__tests__/components/memelab/MemeLabPage.test.tsx(2 hunks)__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferPanel.test.tsx(1 hunks)__tests__/components/the-memes/MemePageYourCards.test.tsx(9 hunks)__tests__/components/user/collected/UserPageCollected.test.tsx(13 hunks)__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx(2 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/components/nft-transfer/TransferPanel.test.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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 propsFollow existing code style and naming conventions
Files:
components/nft-transfer/TransferPanel.tsx__tests__/components/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
components/nft-transfer/TransferPanel.tsx__tests__/components/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.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/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.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/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
{**/__tests__/**,**/*.test.{ts,tsx}}: If coverage on a modified file is below 80%, add meaningful tests to raise it to at least 80%
Mock external dependencies and APIs in tests
Files:
__tests__/components/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx
**/__tests__/**
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directories when organizing standalone test suites
Files:
__tests__/components/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx
**/*.test.tsx
📄 CodeRabbit inference engine (AGENTS.md)
When co-locating tests with components, name them
ComponentName.test.tsx
Files:
__tests__/components/user/collected/UserPageCollected.test.tsx__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx__tests__/components/memelab/MemeLabPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/the-memes/MemePageYourCards.test.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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (6)
components/nft-transfer/TransferPanel.tsx (3)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-926)
__tests__/components/user/collected/UserPageCollected.test.tsx (2)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/user/collected/UserPageCollected.tsx (1)
UserPageCollected(79-554)
__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx (2)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-162)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(17-104)
components/nft-transfer/TransferModal.tsx (6)
components/nft-transfer/TransferState.tsx (1)
useTransfer(164-168)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-926)
__tests__/components/the-memes/MemePageYourCards.test.tsx (2)
__tests__/utils/testContexts.tsx (1)
renderWithProviders(52-63)components/the-memes/MemePageYourCards.tsx (2)
MemePageYourCardsRightMenu(18-254)MemePageYourCardsSubMenu(256-291)
⏰ 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)
__tests__/components/memelab/MemeLabPage.test.tsx (1)
6-7: LGTM! Wagmi imports added for test context.The imports correctly bring in the necessary Wagmi utilities to set up the provider context required by the transfer UI functionality in the "your cards" tab.
__tests__/components/the-memes/MemePageYourCards.test.tsx (3)
1-9: LGTM!The imports are well-organized and include all necessary testing utilities, React Query, and Wagmi dependencies.
232-246: LGTM! Good pattern for extending mock data.The approach of extending
mockTransactionswith additional required fields (gas,contract,transaction, etc.) is a clean pattern that ensures the mock data matches the fullTransactiontype while reusing base test data.
210-229: LGTM!The test suite appropriately covers the component's show/hide logic and conditional rendering based on transaction presence.
__tests__/components/user/collected/UserPageCollected.test.tsx (2)
1-1: LGTM! Clean TransferProvider integration.The introduction of
TransferProviderwrapping via therenderWithTransferProviderhelper is a clean pattern that ensures all tests run within the transfer context. TheSeizeConnectContextmock provides the necessary authentication state for transfer-enabled UI logic.Also applies to: 58-64
125-125: Verify transfer integration tests and coverage in UserPageCollected
- Dedicated transfer tests live under
__tests__/components/nft-transfer/; confirm if UserPageCollected suite needs its own integration tests for transfer flows- Ensure
UserPageCollected.tsxtest coverage meets the 80% threshold__tests__/components/user/collected/cards/UserPageCollectedCards.test.tsx (1)
83-86: LGTM: Provider-wrapped render and explicit mocks make tests robustWrapper via TransferProvider and focused component mocks look good; assertions reflect pagination/empty states correctly.
Also applies to: 90-99, 112-121, 127-136
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
96-121: LGTM: Comprehensive mocks and E2E flow coverage
Mocks for wagmi, identity, image, and provider-less hook usage are set up cleanly; core success/error paths are covered.Also applies to: 128-135
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (8)
components/nft-transfer/TransferModalPfp.tsx (1)
28-56: Use react-query for IPFS resolution (avoid race conditions, follow guideline)Replace useEffect + local state with a useQuery-based hook (e.g., useResolvedIpfsUrl) keyed by src.
As per coding guidelines
components/nft-transfer/TransferState.tsx (1)
28-38: Remove inline comments from TS/TSX per repo rulesDelete the comment lines to comply.
As per coding guidelines
- /** quantity controls */ setQty: (key: string, qty: number) => void; incQty: (key: string) => void; decQty: (key: string) => void; clear: () => void; - /** number of distinct items selected */ count: number; - /** total units selected (sum of qty across items) */ totalQty: number;components/nft-transfer/TransferModal.tsx (6)
575-581: Fix close control semantics and a11yWrap the icon in a button; FontAwesomeIcon doesn’t accept type="button" and isn’t focusable.
- {flow === "review" && enableMockTransfers && ( + {flow === "review" && enableMockTransfers && ( <div className="tw-flex tw-items-center tw-gap-2 tw-text-[12px] tw-opacity-80"> ... </div> )} {(flow === "review" || flow === "success" || flow === "error") && ( - <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80"> + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button> )}
762-785: Fix potential null React key in results listprofile_id can be null; use a non-null fallback (e.g., wallet).
- <button - key={r.profile_id} + <button + key={r.profile_id ?? r.wallet} type="button"
673-686: Replace invalid Tailwind class "tw-border-1" with "tw-border""tw-border-1" is invalid. Use "tw-border".
- className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]" + className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border tw-border-solid tw-border-[#444]" ... - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]"> ... - className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> + className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> ... - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]">Also applies to: 876-887, 898-904
297-303: Early-guard selectedWallet to avoid spurious wallet flowPrevent switching to "wallet" when no destination selected; set proper error and stay in review.
- const handleConfirm = useCallback(async () => { - if (!publicClient || !address) { - setErrorMsg("Client not ready. Please reconnect."); + const handleConfirm = useCallback(async () => { + if (!publicClient || !address || !selectedWallet) { + setErrorMsg(!selectedWallet ? "Please select a destination wallet." : "Client not ready. Please reconnect."); setFlow("error"); return; }
23-26: Remove comments from TSXRepo rule forbids comments in TS/TSX. Delete these comment lines (and any others).
As per coding guidelines
-// DEMO: set to true to simulate transfers locally without opening wallet or sending txs ... - // UI-driven mock controls (default to constants above) ... - // Initial check ... - // Re-check on window resize - // Attach scroll listeners to each scrollable container ... - {/* header */} ... - {/* body */} ... - {/* footer */}Also applies to: 97-102, 217-223, 548-548, 585-585, 872-872
333-337: Critical: contractType comparison uses string, not enumComparing to "ERC1155" will fail if ContractType is an enum. Use the enum constant.
+import { ContractType } from "@/enums"; ... - byContract.set(it.contract, { - is1155: it.contractType === "ERC1155", + byContract.set(it.contract, { + is1155: it.contractType === ContractType.ERC1155, items: [it], label: it.label, });
🧹 Nitpick comments (3)
__tests__/components/nft-transfer/TransferModal.test.tsx (2)
175-209: Strengthen assertions to catch wrong ABI/contract callsAdd expectations for simulateContract args to ensure ERC1155 uses safeBatchTransferFrom and ERC721 uses safeTransferFrom on correct contracts. This would catch regressions.
- await waitFor(() => expect(simulateContract).toHaveBeenCalledTimes(2)); + await waitFor(() => expect(simulateContract).toHaveBeenCalledTimes(2)); + const calls = simulateContract.mock.calls; + expect(calls[0][0]).toMatchObject({ + abi: expect.arrayContaining([expect.objectContaining({ name: "safeBatchTransferFrom" })]), + functionName: "safeBatchTransferFrom", + address: "0x1155", + }); + expect(calls[1][0]).toMatchObject({ + abi: expect.arrayContaining([expect.objectContaining({ name: "safeTransferFrom" })]), + functionName: "safeTransferFrom", + address: "0x721", + });
131-135: Optional: prefer user-event over fireEventFor more realistic interactions (typing/click), use @testing-library/user-event.
Also applies to: 211-222
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferPanel.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferState.test.tsx(1 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferModalPfp.tsx(1 hunks)components/nft-transfer/TransferState.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/components/nft-transfer/TransferState.test.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{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 propsFollow existing code style and naming conventions
Files:
components/nft-transfer/TransferState.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/nft-transfer/TransferModalPfp.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingUse React functional components with hooks for UI components
Files:
components/nft-transfer/TransferState.tsx__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/nft-transfer/TransferModalPfp.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/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.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/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
{**/__tests__/**,**/*.test.{ts,tsx}}: If coverage on a modified file is below 80%, add meaningful tests to raise it to at least 80%
Mock external dependencies and APIs in tests
Files:
__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx
**/__tests__/**
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directories when organizing standalone test suites
Files:
__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.tsx
**/*.test.tsx
📄 CodeRabbit inference engine (AGENTS.md)
When co-locating tests with components, name them
ComponentName.test.tsx
Files:
__tests__/components/nft-transfer/TransferModal.test.tsx__tests__/components/nft-transfer/TransferPanel.test.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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferState.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/nft-transfer/TransferModalPfp.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (4)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(58-924)
__tests__/components/nft-transfer/TransferPanel.test.tsx (1)
components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(16-226)
components/nft-transfer/TransferModal.tsx (6)
components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
components/nft-transfer/TransferModalPfp.tsx (1)
components/ipfs/IPFSContext.tsx (1)
resolveIpfsUrl(67-77)
⏰ 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)
__tests__/components/nft-transfer/TransferPanel.test.tsx (1)
67-118: LGTM — tests align with current component behaviorCovers empty, list, and continue flows; mocking TransferModal is appropriate.
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (4)
components/user/collected/cards/UserPageCollectedCard.tsx (4)
91-91: Fix type safety: coalesce seized_count before formatting.The
formatNumberWithCommasOrDashfunction signature expectsnumber, butcard.seized_countisnumber | null. While the function handles null internally, this creates a TypeScript type mismatch.Apply this diff to ensure type safety:
- {formatNumberWithCommasOrDash(card.seized_count)}x + {formatNumberWithCommasOrDash(card.seized_count ?? 0)}x
123-137: Fix inconsistent ERC1155 selection text display.The selection text logic shows quantity only when
copiesMax === 1but displays just "Selected" for multi-copy tokens (copiesMax > 1). This prevents users from seeing how many copies they selected.Apply this diff to display quantity for all selected items:
<span className="tw-text-sm tw-font-medium"> - {(() => { - if (selected) { - if (copiesMax === 1) { - return `Selected ${qtySelected} / ${copiesMax}`; - } - return "Selected"; - } - - if (copiesMax > 1) { - return `Select (up to ${copiesMax})`; - } - - return "Select"; - })()} + {selected + ? `Selected ${qtySelected} / ${copiesMax}` + : copiesMax > 1 + ? `Select (up to ${copiesMax})` + : "Select"} </span>
114-120: Use tw- prefix for Tailwind classes to match codebase style.The checkbox classes lack the
tw-prefix used throughout the codebase. While thereadOnlyapproach prevents event conflicts, class naming should be consistent.As per coding guidelines
Apply this diff:
<input checked={selected} id={`${card.collection}-${card.token_id}`} type="checkbox" - className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded-sm focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600" + className="tw-w-4 tw-h-4 tw-text-blue-600 tw-bg-gray-100 tw-border-gray-300 tw-rounded-sm focus:tw-ring-blue-500 dark:focus:tw-ring-blue-600 dark:tw-ring-offset-gray-800 focus:tw-ring-2 dark:tw-bg-gray-700 dark:tw-border-gray-600" readOnly />
141-166: Replace icon-based controls with accessible button elements.The plus/minus icons lack proper accessibility: no
role="button", noaria-label, andonClickon non-interactive elements bypasses keyboard navigation.aria-disabledon icons doesn't provide the same functionality as thedisabledprop on buttons.Apply this diff to wrap icons in semantic button elements:
{copiesMax > 1 && qtySelected > 0 && ( <div className="tw-flex tw-items-center tw-gap-1"> - <FontAwesomeIcon - icon={faMinusCircle} - onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - onDecQty?.(); - }} - className="tw-size-5 tw-cursor-pointer" - color={qtySelected <= 1 ? "#60606C" : "#fff"} - aria-disabled={qtySelected <= 1} - /> + <button + type="button" + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + onDecQty?.(); + }} + disabled={qtySelected <= 1} + aria-label="Decrease quantity" + className="tw-bg-transparent tw-border-none tw-p-0 tw-cursor-pointer disabled:tw-cursor-not-allowed"> + <FontAwesomeIcon + icon={faMinusCircle} + className="tw-size-5" + color={qtySelected <= 1 ? "#60606C" : "#fff"} + /> + </button> <div className="tw-min-w-[2ch] tw-text-center tw-text-xs tw-tabular-nums tw-select-none"> {qtySelected} </div> - <FontAwesomeIcon - icon={faPlusCircle} - onClick={(e) => { - e.preventDefault(); - e.stopPropagation(); - onIncQty?.(); - }} - className="tw-size-5 tw-cursor-pointer" - color={qtySelected >= copiesMax ? "#60606C" : "#fff"} - aria-disabled={qtySelected >= copiesMax} - /> + <button + type="button" + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + onIncQty?.(); + }} + disabled={qtySelected >= copiesMax} + aria-label="Increase quantity" + className="tw-bg-transparent tw-border-none tw-p-0 tw-cursor-pointer disabled:tw-cursor-not-allowed"> + <FontAwesomeIcon + icon={faPlusCircle} + className="tw-size-5" + color={qtySelected >= copiesMax ? "#60606C" : "#fff"} + /> + </button> </div> )}
🧹 Nitpick comments (1)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
43-43: Simplify number formatting with Math.round().The current approach converts to string with
toFixed(0), then back to number with unary+. UseMath.round()directly for cleaner code.Apply this diff:
- return formatNumberWithCommasOrDash(+(card.tdh ?? 0).toFixed(0)); + return formatNumberWithCommasOrDash(Math.round(card.tdh ?? 0));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/components/nft-transfer/TransferSingle.test.tsx
- components/nft-transfer/TransferModal.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
**/*.{ts,tsx}: Use TypeScript for source code and follow existing code style and naming conventions
Adhere to clean code standards as measured by SonarQube
Files:
components/user/collected/cards/UserPageCollectedCard.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingImplement React components as functional components using hooks (no class components)
Files:
components/user/collected/cards/UserPageCollectedCard.tsx
🧬 Code graph analysis (1)
components/user/collected/cards/UserPageCollectedCard.tsx (2)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(117-120)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
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 (1)
components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx (1)
56-65: Fix effect dependency: depends on token.id, not ownerThe TDH fetch uses props.token.id; depend on id to refetch correctly.
Apply this diff:
- }, [props.token.owner]); + }, [props.token.id]);
♻️ Duplicate comments (8)
__tests__/components/nft-transfer/TransferSingle.test.tsx (1)
162-170: Good fix: correct +/- test IDs usedSelectors now match component’s data-testids, addressing prior feedback.
components/nft-transfer/TransferModal.tsx (6)
570-576: Fix close control semantics; wrap icon in a buttonFontAwesomeIcon doesn’t accept type and isn’t keyboard-focusable. Wrap with a button for a11y.
Apply this diff:
- {(flow === "review" || flow === "success" || flow === "error") && ( - <FontAwesomeIcon - icon={faXmarkCircle} - type="button" - onClick={handleClose} - size="xl" - /> - )} + {(flow === "review" || flow === "success" || flow === "error") && ( + <button + type="button" + aria-label="Close" + onClick={handleClose} + className="tw-text-white hover:tw-text-white/80" + > + <FontAwesomeIcon icon={faXmarkCircle} size="xl" /> + </button> + )}
669-680: Replace invalid Tailwind class "tw-border-1" with "tw-border""tw-border-1" is not a valid Tailwind class.
Apply this diff:
- className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border-1 tw-border-solid tw-border-[#444]" + className="tw-text-xs tw-rounded-md tw-bg-white/10 hover:tw-bg-white/15 tw-px-2 tw-py-1 tw-border tw-border-solid tw-border-[#444]" @@ - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]"> @@ - className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> + className="tw-rounded-lg tw-bg-white tw-text-black tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444] disabled:tw-opacity-60 disabled:tw-cursor-not-allowed"> @@ - className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border-1 tw-border-solid tw-border-[#444]"> + className="tw-rounded-lg tw-bg-white/10 hover:tw-bg-white/15 tw-px-4 tw-py-2 tw-border tw-border-solid tw-border-[#444]">Also applies to: 884-897, 915-926
23-26: Remove comments from TSX filesProject rule: no comments in TS/TSX. Delete inline and JSX comments.
As per coding guidelines
Also applies to: 97-101, 543-543, 580-581, 878-878
147-184: Refactor search to react-query with debounced keyReplace manual debounce/effect with useQuery keyed by debounced trimmedQuery (enabled when open and length ≥ MIN). Improves cancellation/cache and reduces effect complexity.
As per coding guidelines
768-791: Fix potential null React key for resultsprofile_id can be null; use a non-null fallback (e.g., wallet).
Apply this diff:
- <button - key={r.profile_id} + <button + key={r.profile_id ?? r.wallet} type="button"
316-321: Contract type check uses string literal; compare to enum constantComparing to "ERC1155" can misclassify when ContractType is an enum. Use ContractType.ERC1155 instead.
Apply this diff:
+import { ContractType } from "@/enums"; @@ - byContract.set(it.contract, { - is1155: it.contractType === "ERC1155", + byContract.set(it.contract, { + is1155: it.contractType === ContractType.ERC1155, items: [it], label: it.label, });components/user/collected/UserPageCollected.tsx (1)
239-274: Guard address forcing to avoid redundant router.replace loops (duplicate of past review)This issue was previously flagged and remains unresolved. When transfer is enabled, the effect calls
updateFieldson every render even if the URL already contains the connected address, resulting in repeatedrouter.replacecalls. SincesearchParamsis in the effect dependencies andupdateFieldsmodifies the URL (which updatessearchParams), this creates a loop.Add guards to only call
updateFieldswhen the target address/page actually differs:if (transferEnabled) { if (!hadForcedRef.current) { previousAddressRef.current = currentParamAddress; } hadForcedRef.current = true; - // Force to connected wallet - updateFields([ - { name: "address", value: connected }, - { name: "page", value: "1" }, - ]); + if (currentParamAddress !== connected) { + updateFields([ + { name: "address", value: connected }, + { name: "page", value: "1" }, + ]); + } } else if (hadForcedRef.current) { const restore = previousAddressRef.current; previousAddressRef.current = null; hadForcedRef.current = false; - updateFields([ - { name: "address", value: restore }, - { name: "page", value: "1" }, - ]); + if (restore !== currentParamAddress) { + updateFields([ + { name: "address", value: restore }, + { name: "page", value: "1" }, + ]); + } }
🧹 Nitpick comments (4)
__tests__/components/nft-transfer/TransferSingle.test.tsx (1)
196-201: Prefer user-event over fireEvent for clicksAdopt @testing-library/user-event for realistic user interactions (click, type). Replace fireEvent.click with userEvent.click.
As per coding guidelines
components/nft-transfer/TransferToggle.tsx (1)
33-53: Add aria-pressed for toggle accessibilityExpose pressed state for assistive tech.
Apply this diff:
- <button + <button type="button" + aria-pressed={t.enabled}components/user/collected/UserPageCollected.tsx (2)
240-241: Remove comment per coding guidelinesThe coding guidelines specify no comments in TypeScript/TSX files.
Apply this diff:
- useEffect(() => { - // Only enforce if transfer is available on this profile (owns wallet & not mobile) - if (!showTransfer) return; + useEffect(() => { + if (!showTransfer) return;Based on coding guidelines.
544-544: Remove comment per coding guidelinesThe coding guidelines specify no comments in TypeScript/TSX files.
Apply this diff:
- {/* appears only when transfer is enabled */} {showTransfer && transferEnabled && <TransferPanel />}Based on coding guidelines.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferToggle.test.tsx(1 hunks)components/6529Gradient/GradientPage.tsx(5 hunks)components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx(11 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/nft-transfer/TransferToggle.tsx(1 hunks)components/user/collected/UserPageCollected.tsx(9 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/components/nft-transfer/TransferToggle.test.tsx
- components/nft-transfer/TransferSingle.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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
**/*.{ts,tsx}: Use TypeScript for source code and follow existing code style and naming conventions
Adhere to clean code standards as measured by SonarQube
Files:
components/user/collected/UserPageCollected.tsxcomponents/nft-transfer/TransferToggle.tsx__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/6529Gradient/GradientPage.tsxcomponents/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingImplement React components as functional components using hooks (no class components)
Files:
components/user/collected/UserPageCollected.tsxcomponents/nft-transfer/TransferToggle.tsx__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/6529Gradient/GradientPage.tsxcomponents/nextGen/collections/nextgenToken/NextGenTokenAbout.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/nft-transfer/TransferSingle.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/nft-transfer/TransferSingle.test.tsx
{**/__tests__/**,**/*.test.tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in tests directories or alongside components as ComponentName.test.tsx
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsx
🧠 Learnings (3)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Use react-query for data fetching
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (6)
components/user/collected/UserPageCollected.tsx (6)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)components/nft-transfer/TransferToggle.tsx (1)
TransferToggle(10-55)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(17-104)components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(16-226)
components/nft-transfer/TransferToggle.tsx (3)
hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)
__tests__/components/nft-transfer/TransferSingle.test.tsx (3)
components/nft-transfer/TransferState.tsx (2)
buildTransferKey(174-185)useTransfer(168-172)hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(22-155)
components/nft-transfer/TransferModal.tsx (6)
components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-42)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
components/6529Gradient/GradientPage.tsx (5)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-166)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(22-155)constants.ts (1)
GRADIENT_CONTRACT(10-10)
components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx (1)
components/you-own-nft-badge/YouOwnNftBadge.tsx (1)
YouOwnNftBadge(5-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/nft-transfer/TransferToggle.tsx (1)
10-16: Integration and flow look solidConnect-first handling, clear-on-disable, and mobile guard are correct.
components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx (1)
153-155: Nice: renders ownership badge for connected ownerGood UX detail; consistent with badge component.
components/6529Gradient/GradientPage.tsx (2)
156-170: Solid integration of TransferSingle for owner-only flowsProvider scoping and props are correct; conditional render based on connected owner is appropriate.
66-69: Accurate owner check for connected addressareEqualAddresses guard is correct and efficient.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
components/the-memes/MemePageYourCards.tsx (2)
17-26: Addreadonlykeyword to props parameter.The props parameter should be declared as
readonlyto comply with the coding guidelines for TypeScript files.As per coding guidelines.
Apply this diff:
-export function MemePageYourCardsRightMenu(props: { +export function MemePageYourCardsRightMenu(props: Readonly<{ show: boolean; transactions: Transaction[]; wallets: string[]; nft: NFT | undefined; nftBalance: number; myOwner: ConsolidatedTDH | undefined; myTDH: NftTDH | undefined; myRank: NftRank | undefined; -}) { +}>) {
253-255: Addreadonlykeyword to props parameter.The props parameter should be declared as
readonlyto comply with the coding guidelines for TypeScript files.As per coding guidelines.
Apply this diff:
-export function MemePageYourCardsSubMenu(props: { +export function MemePageYourCardsSubMenu(props: Readonly<{ show: boolean; transactions: Transaction[]; -}) { +}>) {
♻️ Duplicate comments (7)
components/nft-transfer/TransferSingle.tsx (2)
164-167: Fix invalid Tailwind and duplicate paddingReplace tw-border-1 with tw-border and remove duplicate tw-py-* as previously noted.
- className="tw-w-full tw-py-2 tw-rounded-lg tw-bg-white tw-text-black tw-py-1 disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border-1 tw-border-solid tw-border-[#444] tw-text-lg tw-font-semibold" + className="tw-w-full tw-py-2 tw-rounded-lg tw-bg-white tw-text-black disabled:tw-opacity-75 disabled:tw-cursor-not-allowed tw-border tw-border-solid tw-border-[#444] tw-text-lg tw-font-semibold"
71-83: Bug: Ignores provided contract/contractType props; uses mapping insteadThis can register the wrong contract if mappings diverge. Use the props.
useEffect(() => { - t.select({ - key, - contract: COLLECTED_COLLECTION_TYPE_TO_CONTRACT[collectionType], - contractType: COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE[ - collectionType - ] as ContractType, - tokenId, - max, - thumbUrl, - title, - }); + t.select({ + key, + contract, + contractType, + tokenId, + max, + thumbUrl, + title, + });Also add contract/contractType to the effect deps:
- }, [key, collectionType, tokenId, max, thumbUrl, title]); + }, [key, contract, contractType, tokenId, max, thumbUrl, title]);components/nft-transfer/TransferModal.tsx (5)
690-699: Replace invalid Tailwind class "tw-border-1" with "tw-border"Also used in footer buttons.
- className="... tw-border-1 tw-border-solid tw-border-[#444] ..." + className="... tw-border tw-border-solid tw-border-[#444] ..."Also applies to: 919-927
232-270: Use react-query for search instead of manual debounce/fetchGuideline: use react-query for data fetching. Replace the effect with useQuery keyed by debounced trimmedQuery and enabled when open && len>=MIN_SEARCH_LENGTH. Improves caching, cancellation, and simplifies state.
As per coding guidelines
26-29: Remove comments from TSX per project rulesTS/TSX must not contain comments. Delete inline comments across this file (examples in these ranges).
As per coding guidelinesAlso applies to: 100-105, 127-133, 180-186, 207-215, 217-230, 538-546, 561-566, 599-606
787-795: Fix potential null React key for resultsprofile_id can be null; fall back to wallet.
- <button - key={r.profile_id} + <button + key={r.profile_id ?? r.wallet}
138-146: Compare contractType using enum, not stringUse ContractType.ERC1155 to avoid misclassification.
+import { ContractType } from "@/enums"; ... - by.set(it.contract, { - is1155: it.contractType === "ERC1155", + by.set(it.contract, { + is1155: it.contractType === ContractType.ERC1155, items: [it], label: it.label, });
🧹 Nitpick comments (4)
components/the-memes/MemePageYourCards.tsx (1)
137-153: Simplify redundant condition check.The condition at line 137 checks
props.nftBalance > 0 && props.myOwneragain, but this block is already nested inside the condition at line 119 that performs the same checks. Only theprops.nft?.idcheck is new.Apply this diff to simplify:
- {props.nftBalance > 0 && props.myOwner && props.nft?.id && ( + {props.nft?.id && ( <Row className="mb-2">components/nextGen/collections/nextgenToken/NextGenToken.tsx (2)
169-174: Avoid brittle URL .replace for prev/next navigationReplacing the token id in window.location.href can misfire if the id appears elsewhere (query, other path segs). Build the next path explicitly.
Example:
-const currentHref = window.location.href; -const prevHref = currentHref.replace( - props.token.id.toString(), - (props.token.id - 1).toString() -); -router.push(prevHref, { scroll: false }); +const url = new URL(window.location.href); +url.pathname = url.pathname.replace(/\/(\d+)(\/?)$/, `/${props.token.id - 1}$2`); +router.push(url.toString(), { scroll: false });Apply similarly for next token.
Also applies to: 212-217
186-193: Tooltip behavior consistencyPrev tooltip lacks delayShow unlike next. Consider adding the same delay for UX parity.
-<Tooltip - id={`prev-token-${props.token.id}`} - variant="light" +<Tooltip + id={`prev-token-${props.token.id}`} + delayShow={250} + variant="light"components/nft-transfer/TransferModal.tsx (1)
540-547: Add role for modal semanticsSet role="dialog" on the overlay or the modal container for better a11y.
- <div + <div className={[ /* ... */ ].join(" ")} onMouseDown={(e) => { /* ... */ }} aria-modal="true" + role="dialog" aria-label="Transfer dialog">
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
components/6529Gradient/GradientPage.tsx(5 hunks)components/distribution-plan-tool/common/CircleLoader.tsx(1 hunks)components/nextGen/collections/nextgenToken/NextGenToken.tsx(5 hunks)components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx(13 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/the-memes/MemePageYourCards.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- components/distribution-plan-tool/common/CircleLoader.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/6529Gradient/GradientPage.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
**/*.{ts,tsx}: Use TypeScript for source code and follow existing code style and naming conventions
Adhere to clean code standards as measured by SonarQube
Files:
components/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nextGen/collections/nextgenToken/NextGenTokenAbout.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/the-memes/MemePageYourCards.tsxcomponents/nft-transfer/TransferSingle.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingImplement React components as functional components using hooks (no class components)
Files:
components/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nextGen/collections/nextgenToken/NextGenTokenAbout.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/the-memes/MemePageYourCards.tsxcomponents/nft-transfer/TransferSingle.tsx
🧠 Learnings (3)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Use react-query for data fetching
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (5)
components/nextGen/collections/nextgenToken/NextGenToken.tsx (4)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(36-42)constants.ts (1)
NEXTGEN_CONTRACT(6-6)
components/nextGen/collections/nextgenToken/NextGenTokenAbout.tsx (3)
components/auth/Auth.tsx (1)
useAuth(95-97)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/you-own-nft-badge/YouOwnNftBadge.tsx (1)
YouOwnNftBadge(5-24)
components/nft-transfer/TransferModal.tsx (6)
components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)
components/the-memes/MemePageYourCards.tsx (2)
components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(36-42)constants.ts (1)
MEMES_CONTRACT(5-5)
components/nft-transfer/TransferSingle.tsx (5)
components/nft-transfer/TransferState.tsx (3)
TransferProvider(46-166)useTransfer(168-172)buildTransferKey(174-185)hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)entities/IProfile.ts (2)
COLLECTED_COLLECTION_TYPE_TO_CONTRACT(377-385)COLLECTED_COLLECTION_TYPE_TO_CONTRACT_TYPE(387-395)components/nft-transfer/TransferModal.tsx (1)
TransferModal(61-975)
⏰ 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 (2)
components/the-memes/MemePageYourCards.tsx (2)
1-15: LGTM! Import additions support the new transfer functionality.The new imports for TransferSingle, constants (MEMES_CONTRACT, NULL_ADDRESS), types (CollectedCollectionType, ConsolidatedTDH, Transaction, ContractType), and react-bootstrap components are properly organized and align with the transfer UI integration.
171-176: Summary inconsistency: Rank row is still present.The AI summary indicates that a Rank row was removed from the Cards table, but the Rank row is clearly present in the current code. This suggests the summary may not accurately reflect the actual changes.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
__tests__/components/6529Gradient/GradientPage.test.tsx (1)
264-304: Inconsistent test setup: missing SeizeConnectProvider wrapper.This test renders the component directly without using the
renderPage()helper, which means it doesn't wrap the component withSeizeConnectProviderwhile all other tests do. This creates inconsistent test setup and may not accurately reflect the component's behavior in production.Apply this diff to use consistent test setup:
it("handles wallet connection state changes", async () => { - const { rerender } = render( - <TitleProvider> - <AuthContext.Provider value={{ connectedProfile: null } as any}> - <CookieConsentProvider> - <GradientPageComponent id="1" /> - </CookieConsentProvider> - </AuthContext.Provider> - </TitleProvider> - ); + jest.clearAllMocks(); + const collection = mockGradientCollection(3); + collection[0].owner = "0x1"; + (fetchUrl as jest.Mock) + .mockResolvedValueOnce({ data: collection }) + .mockResolvedValueOnce({ data: [tx] }); + + const { rerender } = render( + <TitleProvider> + <AuthContext.Provider value={{ connectedProfile: null } as any}> + <CookieConsentProvider> + <SeizeConnectProvider> + <GradientPageComponent id="1" /> + </SeizeConnectProvider> + </CookieConsentProvider> + </AuthContext.Provider> + </TitleProvider> + ); await waitFor(() => expect(fetchUrl).toHaveBeenCalledTimes(2)); // Should show as non-owner when no connected profile await waitFor(() => expect(screen.getByTestId("image")).toBeInTheDocument() ); await waitFor(() => expect(screen.queryByTestId("owner-badge")).not.toBeInTheDocument() ); // Rerender with connected profile rerender( <TitleProvider> <AuthContext.Provider value={{ connectedProfile: { wallets: [{ wallet: "0x1" }] } } as any}> <CookieConsentProvider> + <SeizeConnectProvider> <GradientPageComponent id="1" /> + </SeizeConnectProvider> </CookieConsentProvider> </AuthContext.Provider> </TitleProvider> ); // Should now show as owner await waitFor(() => expect(screen.getByTestId("image")).toBeInTheDocument() ); await waitFor(() => expect(screen.getByTestId("owner-badge")).toBeInTheDocument() ); });components/nextGen/collections/nextgenToken/NextGenToken.tsx (1)
159-174: Accessibility: make navigation icons real buttonsIcons with onClick are not keyboard-accessible and lack semantics. Use a button with aria-label and disabled state.
- const prev = ( - <FontAwesomeIcon - icon={faChevronCircleLeft} - data-tooltip-id={ - hasPreviousToken ? `prev-token-${props.token.id}` : undefined - } - onClick={() => { + const prev = ( + <button + type="button" + aria-label="Previous token" + data-tooltip-id={hasPreviousToken ? `prev-token-${props.token.id}` : undefined} + disabled={!hasPreviousToken} + onClick={() => { if (!hasPreviousToken) { return; } const url = new URL(window.location.href); url.pathname = url.pathname.replace( /\/(\d+)(\/?)$/, `/${props.token.id - 1}$2` ); - router.push(url.toString(), { scroll: false }); - }} - style={{ - height: "35px", - color: hasPreviousToken ? "#fff" : "#9a9a9a", - cursor: hasPreviousToken ? "pointer" : "default", - }} - /> + router.push(`${url.pathname}${url.search}${url.hash}`, { scroll: false }); + }} + style={{ + height: "35px", + color: hasPreviousToken ? "#fff" : "#9a9a9a", + cursor: hasPreviousToken ? "pointer" : "default", + background: "transparent", + border: "none", + padding: 0 + }} + > + <FontAwesomeIcon icon={faChevronCircleLeft} /> + </button> );Do the analogous change for the “next” button.
Also applies to: 203-218
♻️ Duplicate comments (4)
__tests__/components/the-memes/MemePageYourCards.test.tsx (1)
56-71: This issue was previously flagged and remains unresolved.The
renderWithProvidershelper still has the naming conflict with__tests__/utils/testContexts.tsxand the QueryClient is not configured for optimal test performance. Please refer to the previous review comment for the suggested fix.components/user/collected/UserPageCollected.tsx (1)
239-279: Guarded address forcing avoids router.replace loops.The equality checks before updateFields prevent redirect churn. Good fix.
components/nft-transfer/TransferPanel.tsx (1)
34-41: Remove all inline comments from TSX.TSX must be comment-free. Delete these comments (and any others in the file).
As per coding guidelines
Also applies to: 57-61, 68-76, 213-213
components/nft-transfer/TransferModal.tsx (1)
27-31: Remove all comments in this TSX file.Project rule forbids comments in TS/TSX. Remove the DEMO note and section comments (“header”, “body”, “footer”, etc.).
As per coding guidelines
Also applies to: 855-871, 879-904, 905-989, 990-1056
🧹 Nitpick comments (5)
__tests__/components/6529Gradient/GradientPage.test.tsx (1)
62-74: Consider making the mock more configurable for different test scenarios.The current mock pattern works but has limitations:
- The
SeizeConnectProvidermock doesn't provide the mocked context; it relies on module-level hook mocking- All tests share the same mock return values (e.g.,
address: undefined,isAuthenticated: false)- Tests that need different connection states would require re-mocking
Consider this more flexible pattern:
+const mockSeizeConnect = jest.fn(); +const mockSeizeAcceptConnection = jest.fn(); +let mockContextValue = { + isAuthenticated: false, + seizeConnect: mockSeizeConnect, + seizeAcceptConnection: mockSeizeAcceptConnection, + address: undefined, + hasInitializationError: false, + initializationError: null, +}; + jest.mock("@/components/auth/SeizeConnectContext", () => ({ - useSeizeConnectContext: jest.fn(() => ({ - isAuthenticated: false, - seizeConnect: jest.fn(), - seizeAcceptConnection: jest.fn(), - address: undefined, - hasInitializationError: false, - initializationError: null, - })), + useSeizeConnectContext: jest.fn(() => mockContextValue), SeizeConnectProvider: ({ children }: { children: React.ReactNode }) => ( <>{children}</> ), }));Then tests can update
mockContextValueas needed:it("shows transfer button when connected as owner", () => { mockContextValue.address = "0x1"; mockContextValue.isAuthenticated = true; renderPage(); // assertions... });components/nft-transfer/TransferModal.tsx (1)
590-629: Refactor search to react-query with debounce.Repo rule: use react-query for data fetching. Replace manual setTimeout/AbortController with a debounced query + useQuery (enabled on open and length >= MIN_SEARCH_LENGTH) for caching/cancellation.
As per coding guidelines
Example approach:
- Track debouncedQuery via useEffect/useState (350ms).
- useQuery([QueryKey.COMMUNITY_MEMBERS, debouncedQuery], fetchFn, { enabled: open && debouncedQuery.length >= MIN_SEARCH_LENGTH })
- Derive isSearching from isFetching; setResults from data.
components/nextGen/collections/nextgenToken/NextGenToken.tsx (3)
168-174: Use relative href with router.push to keep client-side routingPassing an absolute URL can bypass Next.js router optimizations. Push a relative path (preserving query/hash).
- router.push(url.toString(), { scroll: false }); + router.push(`${url.pathname}${url.search}${url.hash}`, { scroll: false });Also applies to: 212-218
103-103: Styling: prefer Tailwind utilities in new codeNewly added classes use Bootstrap utilities (pt-4/pb-4, d-md-none, d-none d-md-block). Our TSX guideline is Tailwind for styling; consider Tailwind equivalents (py-4, md:hidden, hidden md:block) where feasible.
As this file mixes React-Bootstrap extensively, confirm whether a local Tailwind-only change is acceptable or whether to defer until a broader styling pass. Based on coding guidelines
Also applies to: 106-117
48-51: Optional: drop useMemo for a simple booleanuseMemo here doesn’t save meaningful work; a direct comparison each render is trivial.
- const isConnectedAddressOwner = useMemo(() => { - return areEqualAddresses(connectedAddress, props.token.owner); - }, [props.token.owner, connectedAddress]); + const isConnectedAddressOwner = areEqualAddresses( + connectedAddress, + props.token.owner + );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
__tests__/components/6529Gradient/GradientPage.test.tsx(3 hunks)__tests__/components/memelab/MemeLabPage.test.tsx(3 hunks)__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)__tests__/components/the-memes/MemePageYourCards.test.tsx(9 hunks)app/network/tdh/historic-boosts/page.client.tsx(1 hunks)app/network/tdh/page.client.tsx(3 hunks)components/nextGen/collections/nextgenToken/NextGenToken.tsx(7 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/user/collected/UserPageCollected.tsx(9 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/components/memelab/MemeLabPage.test.tsx
- components/nft-transfer/TransferSingle.tsx
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{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
**/*.{ts,tsx}: Use TypeScript for source code and follow existing code style and naming conventions
Adhere to clean code standards as measured by SonarQube
Files:
components/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nft-transfer/TransferPanel.tsxapp/network/tdh/historic-boosts/page.client.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/user/collected/UserPageCollected.tsxapp/network/tdh/page.client.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingImplement React components as functional components using hooks (no class components)
Files:
components/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nft-transfer/TransferPanel.tsxapp/network/tdh/historic-boosts/page.client.tsxcomponents/nft-transfer/TransferModal.tsxcomponents/user/collected/UserPageCollected.tsxapp/network/tdh/page.client.tsx__tests__/components/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{app,pages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use NextJS features that match the current version
Files:
app/network/tdh/historic-boosts/page.client.tsxapp/network/tdh/page.client.tsx
app/**
📄 CodeRabbit inference engine (AGENTS.md)
Add all new Next.js production routes under the app/ router (do not add routes under pages/)
Files:
app/network/tdh/historic-boosts/page.client.tsxapp/network/tdh/page.client.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/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.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/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{**/__tests__/**,**/*.test.tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in tests directories or alongside components as ComponentName.test.tsx
Files:
__tests__/components/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/the-memes/MemePageYourCards.test.tsx__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/6529Gradient/GradientPage.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
🧠 Learnings (4)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Use react-query for data fetching
Applied to files:
components/nft-transfer/TransferModal.tsx
📚 Learning: 2025-10-14T05:39:48.871Z
Learnt from: CR
PR: 6529-Collections/6529seize-frontend#0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T05:39:48.871Z
Learning: Applies to {**/__tests__/**,**/*.test.{ts,tsx}} : Mock external dependencies and APIs in tests
Applied to files:
__tests__/components/6529Gradient/GradientPage.test.tsx
🧬 Code graph analysis (8)
components/nextGen/collections/nextgenToken/NextGenToken.tsx (4)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)constants.ts (1)
NEXTGEN_CONTRACT(6-6)
components/nft-transfer/TransferPanel.tsx (3)
components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(420-1056)
components/nft-transfer/TransferModal.tsx (6)
components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)
components/user/collected/UserPageCollected.tsx (6)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)components/nft-transfer/TransferToggle.tsx (1)
TransferToggle(10-55)components/user/collected/cards/UserPageCollectedCards.tsx (1)
UserPageCollectedCards(17-104)components/nft-transfer/TransferPanel.tsx (1)
TransferPanel(16-226)
__tests__/components/the-memes/MemePageYourCards.test.tsx (3)
__tests__/utils/testContexts.tsx (1)
renderWithProviders(52-63)components/auth/SeizeConnectContext.tsx (1)
SeizeConnectProvider(339-616)components/the-memes/MemePageYourCards.tsx (2)
MemePageYourCardsRightMenu(17-251)MemePageYourCardsSubMenu(253-288)
__tests__/components/nft-transfer/TransferSingle.test.tsx (2)
hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)
__tests__/components/6529Gradient/GradientPage.test.tsx (2)
components/auth/SeizeConnectContext.tsx (1)
SeizeConnectProvider(339-616)components/6529Gradient/GradientPage.tsx (1)
GradientPageComponent(40-309)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(420-1056)
⏰ 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 (10)
app/network/tdh/page.client.tsx (1)
55-55: LGTM! Consistent border styling improvements.The border thickness increase from
tw-border-1totw-border-2across these three card containers improves visual consistency and hierarchy. These purely cosmetic changes align with the broader UI standardization effort in the PR.Also applies to: 219-219, 229-229
__tests__/components/6529Gradient/GradientPage.test.tsx (2)
107-109: LGTM!The
SeizeConnectProviderwrapper is correctly positioned in the component tree and enables testing of authentication-related UI states.
116-305: Add test coverage for transfer functionality.The PR objectives mention "Transfer NFTs" and "integrates transfer controls into collected and product pages," but there are no tests verifying the transfer UI. Based on the component code (lines 123-134 in
GradientPage.tsx), theTransferSinglecomponent is conditionally rendered whenisConnectedAddressOwneris true.Add tests to verify:
- Transfer button/component is shown when connected address matches NFT owner
- Transfer component is hidden when connected address doesn't match owner
- Transfer component receives correct props
Example test structure:
it("shows transfer UI when connected address owns the NFT", async () => { // Mock useSeizeConnectContext to return the owner address (useSeizeConnectContext as jest.Mock).mockReturnValue({ address: "0x1", isAuthenticated: true, }); renderPage("0x1"); await waitFor(() => expect(fetchUrl).toHaveBeenCalledTimes(2)); // Verify TransferSingle is rendered (add data-testid to TransferSingle mock) expect(screen.getByTestId("transfer-single")).toBeInTheDocument(); }); it("hides transfer UI when connected address doesn't own the NFT", async () => { (useSeizeConnectContext as jest.Mock).mockReturnValue({ address: "0x2", isAuthenticated: true, }); renderPage("0x1"); await waitFor(() => expect(fetchUrl).toHaveBeenCalledTimes(2)); expect(screen.queryByTestId("transfer-single")).not.toBeInTheDocument(); });Note: You'll also need to add a mock for
TransferSinglecomponent with a testid, and update the mock configuration to allow per-test customization as suggested in the earlier comment.__tests__/components/the-memes/MemePageYourCards.test.tsx (1)
73-277: Test structure and provider usage look good.The tests correctly distinguish between scenarios that require the provider context (when
TransferSinglewould be rendered) and those that don't. The test coverage appropriately exercises the component's conditional rendering logic.app/network/tdh/historic-boosts/page.client.tsx (1)
10-10: LGTM: border class fix is correct.tw-border-2 is valid Tailwind and matches the intended visual change.
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
56-231: Solid coverage of success and error flows.Mocks and assertions exercise ERC1155/721 paths and wallet-unavailable error. Looks good.
__tests__/components/nft-transfer/TransferSingle.test.tsx (1)
128-258: Tests read well and align with component behavior.Covers mount/unmount selection, qty bounds, modal flow, and rerender key updates.
components/nextGen/collections/nextgenToken/NextGenToken.tsx (3)
46-51: Ownership gating looks correctDerives ownership from connected address and token.owner; safe null handling via areEqualAddresses.
58-66: Verified TransferSingle props
TransferSingleProps definesmax: number,title: string, and optionalthumbUrl?: string, matching their usage here.
186-190: Variant and delayShow props are supported react-tooltip v5.28.1 (v5) supports variant="light" and delayShow={250}.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
components/nextGen/collections/nextgenToken/NextGenToken.tsx (1)
106-117: Avoid mounting TransferSingle twice; render a single instance conditionallyRendering the same element in two breakpoints mounts it twice. Render one instance based on a media query.
Example fix:
- <Col xs={12} className="d-md-none"> - {transferSingle} - </Col> + <Col xs={12}> + {!isMdUp ? transferSingle : null} + </Col> @@ - <Col sm={12} md={6}> - <div className="d-none d-md-block">{transferSingle}</div> + <Col sm={12} md={6}> + {isMdUp ? transferSingle : null} <NextgenTokenTraitsAdd a simple hook and usage:
function useMediaQuery(query: string) { const [matches, setMatches] = useState(false); useEffect(() => { const m = window.matchMedia(query); setMatches(m.matches); const handler = (e: MediaQueryListEvent) => setMatches(e.matches); m.addEventListener("change", handler); return () => m.removeEventListener("change", handler); }, [query]); return matches; } const isMdUp = useMediaQuery("(min-width: 768px)");components/nft-transfer/TransferModal.tsx (2)
485-485: Remove comments in TS/TSX to match project rulesProject rule: no comments in TS/TSX. Delete inline and JSX comments across the file.
As per coding guidelines
Also applies to: 869-869, 977-977, 1076-1076, 1140-1140, 1192-1192, 1275-1275, 1310-1310, 1321-1321, 1355-1355
346-347: Make prop readonly (consistency with props policy)Mark searchInputRef as readonly to align with the “always readonly” guideline.
As per coding guidelines
- searchInputRef: React.RefObject<HTMLInputElement | null>; + readonly searchInputRef: React.RefObject<HTMLInputElement | null>;
🧹 Nitpick comments (3)
components/memelab/MemeLabPage.tsx (1)
63-65: Clean up import after removing wrapperRemove TransferProvider import since TransferSingle already provides context.
-import TransferSingle from "../nft-transfer/TransferSingle"; -import { TransferProvider } from "../nft-transfer/TransferState"; +import TransferSingle from "../nft-transfer/TransferSingle";components/nft-transfer/TransferModal.tsx (2)
790-800: Remove duplicate MANIFOLD_CORE_ABI; reuse the top-level constantThe ABI is defined at Lines 72-81 and again inside groupByContractAndOriginator. Keep a single definition.
- // minimal Manifold reads - const MANIFOLD_CORE_ABI = [ - { - type: "function", - name: "tokenExtension", - stateMutability: "view", - inputs: [{ name: "tokenId", type: "uint256" }], - outputs: [{ type: "address" }], - }, - ] as const;And keep using MANIFOLD_CORE_ABI from the module scope.
Also applies to: 72-81
907-909: Avoid console. in production paths*Minimize console.log/warn/error or gate behind a debug flag to keep logs clean.
Also applies to: 938-940, 1074-1074, 1178-1190
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
__tests__/components/NftNavigation.test.tsx(2 hunks)__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/nft-transfer/TransferSingle.test.tsx(1 hunks)components/memelab/MemeLabPage.tsx(4 hunks)components/nextGen/collections/nextgenToken/NextGenToken.tsx(7 hunks)components/nft-navigation/NftNavigation.tsx(4 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)components/the-memes/MemePage.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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
**/*.{ts,tsx}: Use TypeScript for source code and follow existing code style and naming conventions
Adhere to clean code standards as measured by SonarQube
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/memelab/MemeLabPage.tsxcomponents/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nft-navigation/NftNavigation.tsxcomponents/the-memes/MemePage.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsxcomponents/nft-transfer/TransferModal.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for stylingImplement React components as functional components using hooks (no class components)
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsxcomponents/memelab/MemeLabPage.tsxcomponents/nextGen/collections/nextgenToken/NextGenToken.tsxcomponents/nft-navigation/NftNavigation.tsxcomponents/the-memes/MemePage.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsxcomponents/nft-transfer/TransferModal.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/nft-transfer/TransferSingle.test.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.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/nft-transfer/TransferSingle.test.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{**/__tests__/**,**/*.test.tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in tests directories or alongside components as ComponentName.test.tsx
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
{**/__tests__/**,**/*.test.{ts,tsx}}
📄 CodeRabbit inference engine (AGENTS.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/nft-transfer/TransferSingle.test.tsx__tests__/components/NftNavigation.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
🧠 Learnings (3)
📚 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 **/*.{ts,tsx} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Do not include any comments in the code
Applied to files:
components/nft-transfer/TransferModal.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 **/*.{ts,tsx} : Use react-query for data fetching
Applied to files:
components/nft-transfer/TransferModal.tsx
🧬 Code graph analysis (6)
__tests__/components/nft-transfer/TransferSingle.test.tsx (2)
hooks/useDeviceInfo.ts (1)
useDeviceInfo(21-77)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)
components/memelab/MemeLabPage.tsx (3)
components/nft-transfer/TransferState.tsx (1)
TransferProvider(46-166)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)constants.ts (1)
MEMES_CONTRACT(5-5)
components/nextGen/collections/nextgenToken/NextGenToken.tsx (4)
components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)helpers/Helpers.ts (1)
areEqualAddresses(145-150)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)constants.ts (1)
NEXTGEN_CONTRACT(6-6)
__tests__/components/NftNavigation.test.tsx (2)
helpers/Helpers.ts (2)
enterArtFullScreen(168-191)fullScreenSupported(152-166)components/nft-navigation/NftNavigation.tsx (1)
NftNavigation(12-66)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(723-1369)
components/nft-transfer/TransferModal.tsx (7)
components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(13-83)components/nft-transfer/TransferState.tsx (1)
useTransfer(168-172)hooks/useIdentity.ts (1)
useIdentity(18-34)services/api/common-api.ts (1)
commonApiFetch(18-45)helpers/server.helpers.ts (1)
getUserProfile(10-21)
⏰ 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 (28)
components/the-memes/MemePage.tsx (1)
352-352: Query param preservation — LGTMPassing searchParams to NftNavigation aligns with the new params API.
components/memelab/MemeLabPage.tsx (1)
1191-1192: NftNavigation params — LGTMPassing searchParams to preserve query across navigation is correct.
components/nft-transfer/TransferModal.tsx (2)
1116-1127: Good guard for destination walletEarly-returning with a clear error when selectedWallet is missing/invalid is correct.
515-525: Close control semantics — LGTMAccessible button wrapping the icon is correct; no invalid props on FontAwesomeIcon.
__tests__/components/NftNavigation.test.tsx (1)
69-86: Tests for query param preservation — LGTMCovers the new params prop behavior effectively.
components/nft-navigation/NftNavigation.tsx (3)
1-10: LGTM!The new imports (
ReadonlyURLSearchParamsanduseMemo) are correctly used to support query parameter preservation in navigation links.
12-21: LGTM!The optional
paramsprop is correctly typed and follows Next.js conventions for passing search parameters.
49-66: LGTM!The query string is correctly appended to both previous and next navigation links, preserving URL parameters across navigation.
__tests__/components/nft-transfer/TransferModal.test.tsx (7)
1-53: LGTM!Comprehensive mock setup covering all external dependencies. The displayName properties on mocked components are a good practice for debugging.
54-114: LGTM!Test data is well-structured with both ERC1155 and ERC721 items, providing comprehensive coverage for different contract types.
115-174: LGTM!Thorough test setup and cleanup. The
useRealTimerscall inafterEachensures proper cleanup of fake timers used in tests.
176-205: LGTM!The
selectRecipientFlowhelper effectively encapsulates a common test flow with proper fake timer management for debounce testing.
207-211: LGTM!Clear test verifying the UX constraint that prevents transfers without wallet selection.
213-257: LGTM!Comprehensive end-to-end test covering both ERC1155 batch and ERC721 individual transfers with proper wagmi mock interactions and UI verification.
259-274: LGTM!Solid error path testing for wallet unavailability. The broad error message regex on line 271 provides flexibility but ensure it doesn't inadvertently pass with unrelated error messages.
__tests__/components/nft-transfer/TransferSingle.test.tsx (13)
1-20: LGTM!Appropriate mock setup for component testing with proper isolation of external dependencies.
22-54: LGTM!Comprehensive TransferState mock providing full control over state and functions for testing.
56-85: LGTM!The SeizeConnectContext mock pattern using exported
__stateprovides good test controllability, though it's tightly coupled to test needs.
87-98: LGTM!Clean mock setup for device detection with appropriate TypeScript typing.
100-115: LGTM!Thorough reset function ensuring proper test isolation by resetting all mock state and functions.
117-137: LGTM!Well-structured test suite with proper lifecycle management and clear baseline rendering test.
139-143: LGTM!Clear test verifying the component correctly returns null on mobile devices.
145-157: LGTM!Important lifecycle test verifying proper state management during mount/unmount with correct composite key handling.
159-167: LGTM!Correct test verifying +/- controls are hidden when max = 1. The test IDs have been properly fixed as noted in past reviews.
169-186: LGTM!Comprehensive boundary testing for +/- controls with proper accessibility attribute verification at both min and max values.
188-199: LGTM!Solid interaction test verifying that clicking +/- buttons correctly invokes the quantity change callbacks.
201-209: LGTM!Good UX test verifying dynamic button label generation for ERC1155 items with quantity pluralization.
211-256: LGTM!Excellent test coverage of modal and connection flows:
- Immediate modal open when connected
- Connect-first flow with proper state transitions
- Reactivity to prop changes
|
Please retry analysis of this Pull-Request directly on SonarQube Cloud |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
components/nft-transfer/TransferModal.tsx (1)
551-555: Remove inline TSX comments to meet project rules.The TS/TSX guideline forbids comments, yet there are still comment lines here (and elsewhere, e.g., around Lines 872, 1216, 1270, 1403). Please delete these comment lines so the file complies. As per coding guidelines
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
221-229: Strip inline comments from the test file.The no-comments rule for TS/TSX applies here too, but there are multiple
//comments (e.g., Lines 221, 298, 354, 389, 441, 555). Remove them to stay compliant. As per coding guidelines
🧹 Nitpick comments (1)
__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsx (1)
43-62: Test disabled state behavior and overlay messaging for MEMELAB.The test verifies the "N/A" display but doesn't test the disabled state behavior when
copiesMaxis 0. According to the component logic, this should show an overlay message and prevent interaction.Consider adding assertions for:
- Overlay message "Not owned by your connected wallet" when
copiesMaxis 0- Verification that selection controls are not clickable in disabled state
- Testing
isTransferLoadingprop effect on overlay messaging (shows "Loading" spinner)Example assertion for disabled state:
expect( screen.getByText("Not owned by your connected wallet") ).toBeInTheDocument();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
__tests__/components/nft-transfer/TransferModal.test.tsx(1 hunks)__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsx(1 hunks)components/nft-transfer/TransferModal.tsx(1 hunks)
🧰 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:
__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsxcomponents/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferModal.test.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/user/collected/cards/UserPageCollectedCard.test.tsx__tests__/components/nft-transfer/TransferModal.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/user/collected/cards/UserPageCollectedCard.test.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
🧠 Learnings (13)
📚 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/user/collected/cards/UserPageCollectedCard.test.tsx__tests__/components/nft-transfer/TransferModal.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} : Always add readonly before props
Applied to files:
components/nft-transfer/TransferModal.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 **/*.tsx : Use FontAwesome for icons
Applied to files:
components/nft-transfer/TransferModal.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/nft-transfer/TransferModal.tsx__tests__/components/nft-transfer/TransferModal.test.tsx
📚 Learning: 2025-09-28T12:30:53.505Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: .cursor/rules/self_improve.mdc:0-0
Timestamp: 2025-09-28T12:30:53.505Z
Learning: Monitor code review comments for potential rule updates
Applied to files:
components/nft-transfer/TransferModal.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 **/*.tsx : Use TailwindCSS for styling
Applied to files:
components/nft-transfer/TransferModal.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/nft-transfer/TransferModal.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 : Use TypeScript types for request parameters and responses; avoid any unless a third-party payload has no shape guarantees
Applied to files:
components/nft-transfer/TransferModal.tsx
📚 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} : Keep mock implementations minimal—only what’s necessary for the test scenarios
Applied to files:
__tests__/components/nft-transfer/TransferModal.test.tsx
📚 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} : Keep mocks up to date with the real implementations they represent
Applied to files:
__tests__/components/nft-transfer/TransferModal.test.tsx
📚 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/nft-transfer/TransferModal.test.tsx
📚 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} : Review mocks periodically and remove unused mock modules
Applied to files:
__tests__/components/nft-transfer/TransferModal.test.tsx
📚 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} : Document non-obvious expected behaviour directly in the mock file
Applied to files:
__tests__/components/nft-transfer/TransferModal.test.tsx
🧬 Code graph analysis (3)
__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsx (2)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
UserPageCollectedCard(19-343)entities/IProfile.ts (1)
CollectedCard(408-417)
components/nft-transfer/TransferModal.tsx (7)
components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)entities/IProfile.ts (1)
CommunityMemberMinimal(307-318)components/nft-transfer/TransferModalPfp.tsx (1)
TransferModalPfp(12-52)components/nft-transfer/TransferState.tsx (1)
useTransfer(166-170)hooks/useIdentity.ts (1)
useIdentity(18-34)hooks/useDebouncedValue.ts (1)
useDebouncedValue(3-10)helpers/server.helpers.ts (1)
getUserProfile(10-21)
__tests__/components/nft-transfer/TransferModal.test.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(792-1488)
⏰ 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)
__tests__/components/user/collected/cards/UserPageCollectedCard.test.tsx (1)
6-15: Good type safety improvement.The test data is now properly typed as
CollectedCardwithout type casts. This addresses the previous review concern about type safety.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
187-187: Add explicit color prop for icon consistency.The
faCheckicon lacks an explicitcolorprop, while all other FontAwesome icons in the overlay controls (faPlus,faMinusCircle,faPlusCircle) explicitly setcolor="#fff". This inconsistency may cause unexpected rendering behavior in different contexts.Apply this diff:
- <FontAwesomeIcon icon={faCheck} className="tw-size-5" /> + <FontAwesomeIcon icon={faCheck} className="tw-size-5" color="#fff" />components/nft-transfer/TransferSingle.tsx (1)
132-146: Stop flashing 0 quantity before state hydratesWe’re still rendering
{selectedQty}directly, so every mount (and any time the selection map is cleared) shows a brief0/<max>before the effect repopulates the item. Let’s default the display value to1so the UI doesn’t flicker.- const selectedQty = t.selected.get(key)?.qty ?? 0; + const selectedQty = t.selected.get(key)?.qty ?? 0; + const displayQty = selectedQty === 0 ? 1 : selectedQty; … - <div className="tw-min-w-[2ch] tw-text-center tw-text-sm tw-tabular-nums tw-select-none"> - {selectedQty}/{max} + <div className="tw-min-w-[2ch] tw-text-center tw-text-sm tw-tabular-nums tw-select-none"> + {displayQty}/{max} </div>
🧹 Nitpick comments (2)
components/user/collected/cards/UserPageCollectedCard.tsx (1)
138-143: Clarify condition for deselection on decrement.The condition
qtySelected <= 1is defensive but potentially confusing. Since this code is within theisSelectedAndCanSelectbranch,qtySelectedshould always be at least 1 (otherwise the item wouldn't be selected). Using=== 1makes the intent clearer: when decrementing from exactly 1 copy, deselect the item.Apply this diff for clarity:
- if (qtySelected <= 1) { + if (qtySelected === 1) { onDecQty(); onToggle(); } else {__tests__/components/common/TabToggleWithOverflow.test.tsx (1)
13-24: Reuse existing delay helper.There's already a shared
delayhelper atcomponents/waves/drops/wave-drops-all/utils/delay.ts. Importing that here keeps the behavior consistent and avoids another ad‑hoc timer wrapper.-import { act, render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen, waitFor } from "@testing-library/react"; +import { delay } from "@/components/waves/drops/wave-drops-all/utils/delay"; import userEvent from "@testing-library/user-event"; @@ -const delay = (ms: number) => - new Promise((resolve) => setTimeout(resolve, ms)); - const ensureButtonFocused = async (button: HTMLElement) => { await act(async () => { button.focus(); await delay(50); if (document.activeElement !== button) { button.focus(); } }); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
__tests__/components/common/TabToggleWithOverflow.test.tsx(6 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)components/user/collected/cards/UserPageCollectedCard.tsx(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/nft-transfer/TransferPanel.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:
__tests__/components/common/TabToggleWithOverflow.test.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsxcomponents/nft-transfer/TransferSingle.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
__tests__/components/common/TabToggleWithOverflow.test.tsxcomponents/user/collected/cards/UserPageCollectedCard.tsxcomponents/nft-transfer/TransferSingle.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/common/TabToggleWithOverflow.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/common/TabToggleWithOverflow.test.tsx
🧠 Learnings (4)
📚 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/common/TabToggleWithOverflow.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/user/collected/cards/UserPageCollectedCard.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 **/*.tsx : Use TailwindCSS for styling
Applied to files:
components/user/collected/cards/UserPageCollectedCard.tsxcomponents/nft-transfer/TransferSingle.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 **/*.tsx : Use FontAwesome for icons
Applied to files:
components/user/collected/cards/UserPageCollectedCard.tsx
🧬 Code graph analysis (3)
__tests__/components/common/TabToggleWithOverflow.test.tsx (1)
components/waves/drops/wave-drops-all/utils/delay.ts (1)
delay(1-4)
components/user/collected/cards/UserPageCollectedCard.tsx (3)
entities/IProfile.ts (1)
CollectedCard(408-417)helpers/Helpers.ts (1)
formatNumberWithCommasOrDash(121-124)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)
components/nft-transfer/TransferSingle.tsx (4)
components/nft-transfer/TransferState.tsx (3)
TransferProvider(44-164)useTransfer(166-170)buildTransferKey(172-183)hooks/useDeviceInfo.ts (1)
useDeviceInfo(23-93)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/nft-transfer/TransferModal.tsx (1)
TransferModal(792-1488)
⏰ 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)
__tests__/components/common/TabToggleWithOverflow.test.tsx (1)
91-139: Great keyboard coverage.Nice job exercising the overflow trigger via keyboard, including both Enter and Space paths and asserting the aria-expanded transitions—it gives strong confidence in the accessible interaction.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
components/nft-transfer/TransferPanel.tsx (1)
245-246: Consider defensive handling for key format.The code assumes
it.keyalways follows the"collection:tokenId"format. IfbuildTransferKeyguarantees this format, document it. Otherwise, add validation to handle malformed keys gracefully.Apply this diff to add defensive handling:
- const [collection, tokenId] = it.key.split(":"); - const label = `${collection} #${tokenId}`; + const parts = it.key.split(":"); + const label = parts.length === 2 + ? `${parts[0]} #${parts[1]}` + : it.title ?? it.key;components/memelab/MemeLabPage.tsx (1)
171-172: Refactor duplicated wallet extraction logic.The wallet extraction pattern appears twice (lines 171-172 and lines 561-562). Extract this to a
useMemoat the component level to avoid duplication and ensure consistency.Apply this refactor:
+ const wallets = useMemo(() => { + const walletObjects = connectedProfile?.wallets ?? []; + return walletObjects.map((w) => w.wallet); + }, [connectedProfile?.wallets]); + useEffect(() => { - const walletObjects = connectedProfile?.wallets ?? []; - const wallets = walletObjects.map((w) => w.wallet); if (wallets.length > 0 && nftId) {And remove the duplicate at lines 561-562:
function printYourCards() { const firstAcquired = [...transactions].sort((a, b) => a.transaction_date > b.transaction_date ? 1 : -1 )[0]; const airdropped = transactions.filter( (t) => t.value === 0 && areEqualAddresses(t.from_address, NULL_ADDRESS) ); - const walletObjects = connectedProfile?.wallets ?? []; - const wallets = walletObjects.map((w) => w.wallet); const transferredIn =Also applies to: 561-562
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
components/memelab/MemeLabPage.tsx(9 hunks)components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferSingle.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- components/nft-transfer/TransferSingle.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/nft-transfer/TransferPanel.tsxcomponents/memelab/MemeLabPage.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
components/nft-transfer/TransferPanel.tsxcomponents/memelab/MemeLabPage.tsx
🧠 Learnings (2)
📚 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/nft-transfer/TransferPanel.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 **/*.tsx : Use TailwindCSS for styling
Applied to files:
components/nft-transfer/TransferPanel.tsx
🧬 Code graph analysis (2)
components/nft-transfer/TransferPanel.tsx (1)
components/nft-transfer/TransferModal.tsx (1)
TransferModal(792-1488)
components/memelab/MemeLabPage.tsx (2)
services/6529api.ts (1)
fetchAllPages(22-37)components/nft-transfer/TransferSingle.tsx (1)
TransferSingle(32-38)
⏰ 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 (2)
components/memelab/MemeLabPage.tsx (2)
653-665: LGTM!The TransferSingle integration is correct:
- Uses MEMELAB_CONTRACT ✅
- Uses CollectedCollectionType.MEMELAB ✅
- No unnecessary TransferProvider wrapper ✅
- Conditional rendering is appropriate ✅
227-227: LGTM!The generic typing for
fetchAllPages<NFTHistory>correctly matches the refactored API helper signature.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
components/nft-transfer/TransferState.tsx (1)
34-34: Remove comment per coding guidelines.This inline comment was flagged in a previous review and marked as addressed in commit 520c4b2, but it still remains in the code.
Apply this diff:
- /** quantity controls */ setQty: (key: string, qty: number) => void;As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
components/nft-transfer/TransferPanel.tsx(1 hunks)components/nft-transfer/TransferState.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/nft-transfer/TransferPanel.tsxcomponents/nft-transfer/TransferState.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
components/nft-transfer/TransferPanel.tsxcomponents/nft-transfer/TransferState.tsx
🧠 Learnings (3)
📚 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/nft-transfer/TransferPanel.tsxcomponents/nft-transfer/TransferState.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 **/*.tsx : Use TailwindCSS for styling
Applied to files:
components/nft-transfer/TransferPanel.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/nft-transfer/TransferState.tsx
🧬 Code graph analysis (1)
components/nft-transfer/TransferPanel.tsx (4)
components/nft-transfer/TransferState.tsx (1)
useTransfer(201-205)components/auth/SeizeConnectContext.tsx (1)
useSeizeConnectContext(618-626)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)components/nft-transfer/TransferModal.tsx (1)
TransferModal(792-1488)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
components/nft-transfer/TransferState.tsx (2)
34-34: Remove the inline comment.The inline comment violates the coding guidelines for TS/TSX files.
Apply this diff:
- /** quantity controls */ setQty: (key: string, qty: number) => void;As per coding guidelines
60-60: Fix the type signature to support functional updates.The callback type only accepts
boolean, but line 151 passes a function(v) => !v. This breaks the functional state update pattern and will cause a type error.Apply this diff to fix the type:
- const setEnabledStable = useCallback((v: boolean) => setEnabledRaw(v), []); + const setEnabledStable = useCallback( + (v: boolean | ((prev: boolean) => boolean)) => setEnabledRaw(v), + [] + );
🧹 Nitpick comments (1)
components/nft-transfer/TransferState.tsx (1)
100-105: Consider simplifying the Map construction.The code creates an intermediate array with
Array.from(next.entries())which is unnecessary—you can iteratenextdirectly.Apply this diff to iterate directly:
const newMap = new Map(); newMap.set(item.key, newItem); - for (const [key, value] of Array.from(next.entries())) { + for (const [key, value] of next) { newMap.set(key, value); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (1)
components/nft-transfer/TransferState.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/nft-transfer/TransferState.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursorrules)
**/*.tsx: Use FontAwesome for icons
Use TailwindCSS for styling
Files:
components/nft-transfer/TransferState.tsx
🧠 Learnings (2)
📚 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/nft-transfer/TransferState.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/nft-transfer/TransferState.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
components/nft-transfer/TransferState.tsx (4)
1-10: LGTM!The imports and client directive are appropriate for a stateful React context provider.
46-58: LGTM!The clamp utility is correct, and the provider initialization properly uses readonly props.
154-196: LGTM!The derived values and memoized API are correctly structured with appropriate dependencies.
198-220: LGTM!The provider return, useTransfer hook, and buildTransferKey utility follow React best practices correctly.
|







Summary by CodeRabbit