Conversation
Signed-off-by: prxt6529 <prxt@6529.io>
📝 WalkthroughWalkthroughReplaces modal-confirm flows with direct action handlers; requires confirmed token IDs for subscription actions; centralizes multipart upload core with retries/concurrency and exports uploadDistributionPhotos; adds OpenAPI photo endpoints; raises upload limit to 500MB; adds CSV header-aware parsing; updates tests and title-setting effect. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser
participant Frontend
participant Backend
participant S3
Note over User,Browser: User selects files and clicks Upload
User->>Browser: choose files & click Upload
Browser->>Frontend: uploadDistributionPhotos({contract, tokenId, files, onProgress})
alt All files small (presigned PUT)
Frontend->>Backend: POST /distribution_photos/{contract}/{tokenId}/prep
Backend-->>Frontend: { upload_url }
Frontend->>S3: PUT file to presigned URL (progress)
S3-->>Frontend: 200 OK (returns media_url)
else Any large files (multipart)
Frontend->>Backend: POST /distribution_photos/{contract}/{tokenId}/multipart-upload (start)
Backend-->>Frontend: { upload_id, key }
par Upload parts concurrently
loop per part
Frontend->>Backend: POST /multipart-upload/part (get part URL)
Backend-->>Frontend: { part_presigned_url }
Frontend->>S3: PUT part to presigned URL (part progress, returns ETag)
S3-->>Frontend: 200 + ETag
end
end
Frontend->>Backend: POST /multipart-upload/completion (submit parts ETags)
Backend-->>Frontend: { media_url }
end
Frontend->>Backend: POST /distribution_photos/{contract}/{tokenId}/complete (save media URLs)
Backend-->>Frontend: 200 OK
Frontend-->>Browser: resolve with media URLs, emit final onProgress
Browser->>User: show success toast & refresh overview
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
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: 2
Fix all issues with AI Agents 🤖
In @services/distribution/distributionPhotoUpload.ts:
- Around line 192-201: Guard against division by zero in the progress
calculation by handling the case where totalSize === 0 before computing percent:
compute totalSize from files as now, but in handleProgress (or when calling
onProgress) check if totalSize is 0 and if so call onProgress(100) (or 0
depending on desired semantics) instead of performing (overallUploaded /
totalSize); update the handleProgress function that references totalSize,
overallUploaded, files, and onProgress to short-circuit when totalSize is zero
to avoid division by zero.
- Around line 109-149: The progress delta bug is caused by lastChunkLoaded
persisting across retries; inside uploadChunk (or immediately before the
axios.put call) reset lastChunkLoaded to 0 or use a local per-attempt variable
(e.g., lastChunkLoadedLocal) so the onUploadProgress callback computes deltas
from the start of the current attempt; ensure this change is applied for each
part upload (references: lastChunkLoaded, uploadChunk, onUploadProgress,
axios.put, partNumber, blobPart) so retries don't inherit prior loaded values or
pollute other part uploads.
🧹 Nitpick comments (7)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx (1)
77-91: Minor: Mixed utility class conventions.The button mixes Bootstrap classes (
d-flex,gap-2,align-items-center) with Tailwind classes (tw-*). Consider using consistent class conventions.🔎 Suggested refactor for consistency
{downloading ? ( - <span className="d-flex gap-2 align-items-center"> + <span className="tw-flex tw-gap-2 tw-items-center"> <CircleLoader /> <span>Downloading</span> </span>services/distribution/distributionPhotoUpload.ts (1)
205-217: Consider parallel file uploads for better performance.Files are uploaded sequentially. For multiple large files, parallel uploads (with bounded concurrency) could significantly improve overall upload time.
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx (1)
234-234: Consider adding a header row to the example for clarity.The format hint shows
address,valuebut the example doesn't include a header row. Adding a header to the example would demonstrate that headers are supported.🔎 Suggested example update
<code> - {`0x33FD426905F149f8376e227d0C9D3340AaD17aF1,5 + {`address,value +0x33FD426905F149f8376e227d0C9D3340AaD17aF1,5 0x9f6ae0370d74f0e591c64cec4a8ae0d627817014,10`} </code>components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
379-383: Inconsistent error typing: useunknowninstead ofany.Other error handlers in this file use
error: unknown(lines 98, 141, 324), but this one useserror: any. For consistency and type safety, preferunknown.🔎 Proposed fix
- } catch (error: any) { + } catch (error: unknown) { const errorMessage = typeof error === "string" ? error - : error?.message || "Something went wrong."; + : error instanceof Error + ? error.message + : "Something went wrong.";openapi.yaml (2)
329-518: Distribution-photo upload endpoints are consistent with existing media APIsThe new
/distribution_photos/{contract}/{nft_id}upload and multipart endpoints correctly mirror the existing/drop-mediaand/wave-mediapatterns (same request/response schemas, 201 status, and auth description). Consider optionally adding explicit404responses for non‑existentcontract/nft_idto match other resource-specific paths, but this is not required for correctness.
9131-9161: Completion request/response schemas for distribution photos look sound
DistributionPhotoCompleteRequestPhotoandDistributionPhotoCompleteRequestenforce at least onemedia_url, andDistributionPhotoCompleteResponsereturns a simple{ success, photos: string[] }payload, which is easy to consume and aligns with the/completeendpoint semantics. The CloudFront URL descriptions are clear; just ensure backend responses actually use that host.__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx (1)
45-55: Footer tests comprehensively cover the new direct admin flows
- The
ConfirmTokenIdModalmock now callingprops.onConfirm("123")aligns with the simplifiedonConfirm(tokenId: string)contract and drives the admin state inTestWrapperwithout coupling to the real modal.shows upload modals when upload buttons clickedcorrectly verifies that both the Distribution Photos and Automatic Airdrops modals are wired and toggle from the new buttons.- The
resetSubscriptionsandfinalizeDistributiontests properly mockcommonApiPost/commonApiFetch, assert that the right endpoints (containing/resetand/normalize) are hit, and confirm the success toasts, so the new non‑modal flows are well covered and external APIs are mocked as per testing guidelines. Based on learnings, this matches the “mock external dependencies and APIs in tests” requirement.If you want slightly stricter isolation, you could clear
authCtx.setToastin abeforeEachfor this file so toast expectations never depend on calls from earlier tests, but it’s not strictly necessary.Also applies to: 134-156, 176-246
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
generated/models/DistributionPhotoCompleteRequest.tsis excluded by!**/generated/**generated/models/DistributionPhotoCompleteRequestPhoto.tsis excluded by!**/generated/**generated/models/DistributionPhotoCompleteResponse.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**
📒 Files selected for processing (9)
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxopenapi.yamlservices/distribution/distributionPhotoUpload.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxservices/distribution/distributionPhotoUpload.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run testto execute all Jest tests and enforce ≥80% line coverage for files changed sincemain. Tests must pass and coverage threshold must be met before completing any task.Enforce ≥ 80% line coverage for files changed since
mainby runningnpm run test
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxservices/distribution/distributionPhotoUpload.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxservices/distribution/distributionPhotoUpload.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxservices/distribution/distributionPhotoUpload.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/{__tests__,*.test.{tsx,ts}}
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directory or asComponentName.test.tsxalongside the component
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{test,spec}.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxservices/distribution/distributionPhotoUpload.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins
Files:
services/distribution/distributionPhotoUpload.ts
🧠 Learnings (3)
📚 Learning: 2025-12-30T14:31:52.993Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:52.993Z
Learning: Applies to **/__tests__/**/*.{test,spec}.{ts,tsx,js,jsx}|**/*.{test,spec}.{ts,tsx,js,jsx} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` files. Mock external dependencies and APIs in tests.
Applied to files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
📚 Learning: 2025-12-30T14:32:37.293Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.293Z
Learning: Applies to __tests__/**/*.{ts,tsx,js},!**/__tests__/**,!**/__mocks__/**,!**/*.d.ts : Avoid double negatives in code; prefer explicit statements and use optional chaining (`?.`)
Applied to files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
📚 Learning: 2025-12-30T14:32:19.339Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.339Z
Learning: Applies to **/*.{test,spec}.{tsx,ts} : Mock external dependencies and APIs in tests
Applied to files:
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx
🧬 Code graph analysis (4)
services/distribution/distributionPhotoUpload.ts (7)
generated/models/ApiCreateMediaUploadUrlRequest.ts (1)
ApiCreateMediaUploadUrlRequest(16-44)generated/models/ApiCreateMediaUrlResponse.ts (1)
ApiCreateMediaUrlResponse(16-51)generated/models/ApiStartMultipartMediaUploadResponse.ts (1)
ApiStartMultipartMediaUploadResponse(16-44)generated/models/ApiUploadPartOfMultipartUploadRequest.ts (1)
ApiUploadPartOfMultipartUploadRequest(16-51)generated/models/ApiCompleteMultipartUploadRequest.ts (1)
ApiCompleteMultipartUploadRequest(17-52)generated/models/ApiCompleteMultipartUploadResponse.ts (1)
ApiCompleteMultipartUploadResponse(16-37)generated/models/DistributionPhotoCompleteRequest.ts (1)
DistributionPhotoCompleteRequest(17-38)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
services/distribution/distributionPhotoUpload.ts (1)
uploadDistributionPhotos(186-230)
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx (2)
tests/testHelpers.ts (1)
test(4-11)components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx (1)
isSubscriptionsAdmin(94-100)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx (3)
components/distribution-plan-tool/review-distribution-plan/table/constants.ts (1)
PUBLIC_SUBSCRIPTIONS_PHASE_ID(1-1)constants.ts (1)
MEMES_CONTRACT(5-5)components/distribution-plan-tool/common/CircleLoader.tsx (1)
CircleLoader(9-39)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsx (1)
38-38: LGTM! File size limit increase aligns with new multipart upload support.The 500MB limit is appropriate given the new
distributionPhotoUpload.tsservice that handles multipart uploads for files ≥ 5MB, enabling efficient upload of large distribution photos.Also applies to: 61-63
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscription.test.tsx (2)
66-72: LGTM! Test contexts properly reflect the new token-confirmation gating.The mock contexts (
mockDistCtxWithTokenIdandmockDistCtxNoTokenId) correctly test both states for the new gating condition requiringconfirmedTokenId.
197-244: LGTM! Loading state test correctly uses deferred promise pattern.The test properly verifies the loading state by controlling promise resolution timing. The pattern ensures the "Downloading" text appears during the async operation.
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscription.tsx (3)
40-46: LGTM! Proper gating with confirmedTokenId requirement.The component correctly returns early when the token ID is not confirmed, preventing download attempts without a valid token ID.
51-74: LGTM! Clean direct download handler with proper error handling.The
handleDownloadfunction correctly manages loading state, invokes the download, and provides toast feedback for both success and error cases.
102-125: LGTM! Download function with comprehensive error handling.The function properly returns a result object with success/failure status and handles both successful responses and exceptions gracefully.
services/distribution/distributionPhotoUpload.ts (3)
1-19: LGTM! Well-structured constants and imports.The constants are appropriately defined:
- 5MB threshold aligns with S3 multipart minimum
- 5 concurrent uploads balances throughput and resource usage
- 3 retries with exponential backoff is a sensible default
35-74: LGTM! Simple upload path is well-implemented.The function correctly:
- Requests a presigned URL from the API
- Uploads with proper Content-Type header
- Tracks upload progress via delta calculation
- Validates required response fields
142-146: Verify S3 bucket CORS configuration exposes the ETag header.The ETag header must be accessible from the S3 presigned URL response. S3 presigned URLs do not bypass CORS enforcement, so the bucket's CORS configuration must include
ETagin theExposeHeaderslist. The code correctly fails fast if the ETag is missing, but this depends entirely on proper backend S3 configuration.components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx (3)
49-55: LGTM! Header detection is user-friendly.The
isHeaderRowfunction correctly identifies common header patterns (address/wallet,count/value), allowing users to upload CSVs with or without headers.
57-109: LGTM! Parser correctly handles headers and reports accurate line numbers.The
lineOffsetcalculation ensures error messages reference the correct line number in the original file, accounting for whether a header was present.
169-174: LGTM! CSV reconstruction ensures consistent format.Rebuilding the CSV from parsed rows guarantees the backend receives a clean, normalized format without headers, regardless of input variations.
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (3)
114-155: LGTM! Clean finalize distribution implementation.The function properly:
- Manages loading state
- Posts to the normalize endpoint
- Handles both success/failure response fields
- Provides appropriate toast feedback
- Refreshes overview on success
193-196: LGTM! Direct action is cleaner than modal flow.The inline
onClickhandler that directly callsresetSubscriptionssimplifies the UX while maintaining the null-check fordistributionPlan.
313-323: LGTM! Properly integrated new upload service.The
uploadDistributionPhotosservice is correctly used, and the success message appropriately reports the count of uploaded photos.__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.test.tsx (1)
53-69: UpdatedonConfirmexpectations correctly reflect new callback signatureAsserting
mockOnConfirmis called with a single"123"argument for both the Confirm button and Enter key paths matches the simplifiedonConfirm(tokenId)contract and keeps coverage for both interaction modes.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
components/waves/create-wave/services/multiPartUpload.ts (1)
28-34: Consider: Division by zero for 0-byte files.If
file.sizeis 0, the calculation at line 31 would result in division by zero. While 0-byte files are an edge case, the check at line 20 only validates the maximum size, not the minimum.🔎 Suggested fix
const handleProgress = (bytesUploaded: number) => { overallUploaded += bytesUploaded; if (onProgress) { + if (file.size === 0) { + onProgress(100); + return; + } const percent = Math.floor((overallUploaded / file.size) * 100); onProgress(percent); } };services/distribution/distributionPhotoUpload.ts (1)
108-120: Sequential upload is intentional but may be slower for multiple files.Files are uploaded one at a time. If faster multi-file uploads are desired, consider parallel processing with concurrency control (similar to the part uploads in multipartUploadCore). However, sequential uploads provide simpler progress tracking and lower resource usage, so this may be intentional.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
components/distribution/Distribution.tsxcomponents/waves/create-wave/services/multiPartUpload.tsservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
components/distribution/Distribution.tsxservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/distribution/Distribution.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/distribution/Distribution.tsxservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
components/distribution/Distribution.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
components/distribution/Distribution.tsxservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/distribution/Distribution.tsxservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/distribution/Distribution.tsxservices/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
**/*.{ts,js}
📄 CodeRabbit inference engine (AGENTS.md)
When parsing Seize URLs or similar, fail fast if base origin is unavailable instead of falling back to placeholder origins
Files:
services/distribution/distributionPhotoUpload.tsservices/uploads/multipartUploadCore.tscomponents/waves/create-wave/services/multiPartUpload.ts
🧬 Code graph analysis (3)
components/distribution/Distribution.tsx (1)
contexts/TitleContext.tsx (1)
useTitle(201-207)
services/distribution/distributionPhotoUpload.ts (5)
generated/models/ApiCreateMediaUploadUrlRequest.ts (1)
ApiCreateMediaUploadUrlRequest(16-44)generated/models/ApiCreateMediaUrlResponse.ts (1)
ApiCreateMediaUrlResponse(16-51)services/uploads/multipartUploadCore.ts (1)
multipartUploadCore(63-171)generated/models/DistributionPhotoCompleteRequest.ts (1)
DistributionPhotoCompleteRequest(17-38)generated/models/DistributionPhotoCompleteResponse.ts (1)
DistributionPhotoCompleteResponse(16-44)
components/waves/create-wave/services/multiPartUpload.ts (1)
services/uploads/multipartUploadCore.ts (1)
multipartUploadCore(63-171)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (12)
components/distribution/Distribution.tsx (1)
105-109: LGTM!The useEffect correctly sets the document title when
isValidNftIdandnftIdare truthy, and includes all necessary dependencies. The title format matches the component's display pattern.services/uploads/multipartUploadCore.ts (4)
1-15: LGTM - Well-structured constants.The constants are appropriate for S3 multipart uploads (5MB minimum part size, reasonable concurrency and retry settings).
29-61: LGTM - Good fallback handling for content types.The function properly prioritizes the browser-provided MIME type and falls back to extension-based detection for common media types used in distribution contexts.
96-136: Consider: Progress may over-report on retry.If a part upload fails mid-way and retries, the
onUploadProgresscallback will report bytes that were already counted in the failed attempt. This could cause progress to temporarily exceed 100% or display jumpy behavior in the UI.Since
lastChunkLoadedis correctly scoped insideuploadChunk, each retry starts fresh at 0, but cumulative progress across all parts (tracked by callers) doesn't account for the failed attempt's partial bytes.This is acceptable for most use cases but worth noting if precise progress tracking is required.
148-171: LGTM - Proper completion handling.The completion request correctly includes all part numbers and ETags, with appropriate validation of the returned media URL.
components/waves/create-wave/services/multiPartUpload.ts (2)
2-5: LGTM - Good refactor to use centralized upload core.Clean extraction of multipart upload logic to a reusable module, improving maintainability across the codebase.
36-49: LGTM - Clean delegation to core with proper endpoint configuration.The endpoint paths are correctly constructed and the return type properly maps the media URL and content type.
services/distribution/distributionPhotoUpload.ts (5)
1-9: LGTM - Clean imports and threshold configuration.The threshold aligns with S3's minimum part size for multipart uploads.
25-64: LGTM - Simple upload path implementation.Correctly handles presigned URL flow with proper progress delta reporting and validation of server responses.
66-83: LGTM - Clean delegation to multipartUploadCore.The spread syntax for optional onProgress is a nice touch for conditional inclusion.
94-104: LGTM - Division by zero guard properly implemented.The
totalSize === 0check at line 97 correctly addresses the edge case where files array is empty or all files have zero size, as noted in previous review.
122-133: No changes needed—the property mapping is correct.The code correctly maps each URL to
{ media_url: url }, which matches theDistributionPhotoCompleteRequestPhototype definition. The type expectsmedia_urlas a required string property, as confirmed in both the OpenAPI schema and the generated TypeScript class.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (2)
22-30: LGTM - Consider extracting to shared utilities.The error normalization logic is solid and handles common error types appropriately. This pattern is useful across the codebase and could be extracted to a shared utility file (e.g.,
helpers/errorUtils.ts) for reuse in other components.
303-330: Consider adding upload progress feedback.The
uploadDistributionPhotosservice supports anonProgresscallback (perdistributionPhotoUpload.ts), but it's not utilized here. Given the PR increases the upload limit to 500MB, users uploading large files won't receive progress feedback during potentially lengthy uploads.🔎 Proposed enhancement to add progress tracking
+ const [uploadProgress, setUploadProgress] = useState(0); ... onUpload={async ( contract: string, tokenId: string, files: File[] ) => { setShowUploadPhotos(false); setIsUploading(true); + setUploadProgress(0); try { const uploadedUrls = await uploadDistributionPhotos({ contract, tokenId, files, + onProgress: (percent) => setUploadProgress(percent), });Then display
uploadProgressin the button's loading state.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
🧬 Code graph analysis (1)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
services/distribution/distributionPhotoUpload.ts (1)
uploadDistributionPhotos(85-133)
⏰ 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/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (4)
118-153: LGTM!The
finalizeDistributionfunction is well-structured with proper loading state management, dual-layer error handling (API response errors and network exceptions), and correct state refresh on success.
191-194: Verify: Intentional removal of confirmation for destructive action?The reset button now directly invokes
resetSubscriptionswithout a confirmation dialog. Since this is a destructive operation that resets subscription data, accidental clicks could cause data loss.Please confirm this is intentional. If not, consider adding a confirmation step (e.g.,
window.confirm()or a modal) before proceeding with the reset.
263-264: LGTM!Direct invocation for finalize is appropriate as it's an idempotent operation. The button is properly disabled during the async operation.
371-375: LGTM!Consistent error handling using the
getErrorMessagehelper.
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/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx (1)
57-110: Clarify terminology in error messages to match header detection flexibility.The code's
isHeaderRowfunction (line 53) accepts both "count" and "value" as valid second column names, but error message at line 81 hardcodes "address,count". When the UI hint at line 235 shows "address,value", users may submit a valid CSV with that header, only to see an error message referencing "count" instead, creating confusion.Update the error message to reflect both accepted formats (e.g., "Expected format "address,count" or "address,value"") or standardize terminology across all user-facing text and error messages.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.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 (3)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx (3)
49-55: LGTM! Header detection logic is sound.The
isHeaderRowfunction correctly handles flexible header formats by accepting both "address"/"wallet" and "count"/"value" variations with case-insensitive matching.
135-137: LGTM! Correctly adapted to new parseCsv return type.The destructuring of
{ rows }properly handles the updated signature.
170-173: CSV reconstruction maintains "count" terminology.The reconstruction correctly normalizes the CSV data from parsed rows. However, note that line 171 uses
${row.count}, maintaining the "count" field name. This is consistent with the internal data structure but inconsistent with the UI hint showing "address,value" at line 235.This reconstruction approach is appropriate for ensuring clean upload format.
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
__tests__/components/distribution/Distribution.test.tsx (1)
27-27: Consider removing explanatory comments per coding guidelines.The coding guidelines specify that code should be self-explanatory without comments for TypeScript files. While these comments add clarity to the test setup, consider whether the code structure and naming alone can convey the same information.
That said, comments in test files are often valuable for explaining complex setup or test intent, so this is a lower-priority style suggestion.
As per coding guidelines for
**/*.{ts,tsx,js,jsx}: "Do not include any comments in the code; it should be self-explanatory"Also applies to: 33-33, 42-42, 50-50, 158-158
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
__tests__/components/distribution/Distribution.test.tsx
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run testto execute all Jest tests and enforce ≥80% line coverage for files changed sincemain. Tests must pass and coverage threshold must be met before completing any task.Enforce ≥ 80% line coverage for files changed since
mainby runningnpm run test
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
__tests__/components/distribution/Distribution.test.tsx
**/{__tests__,*.test.{tsx,ts}}
📄 CodeRabbit inference engine (AGENTS.md)
Place tests in
__tests__/directory or asComponentName.test.tsxalongside the component
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{test,spec}.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Mock external dependencies and APIs in tests
Files:
__tests__/components/distribution/Distribution.test.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
__tests__/components/distribution/Distribution.test.tsx
🧠 Learnings (7)
📚 Learning: 2025-12-30T14:32:19.339Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.339Z
Learning: Applies to **/*.{test,spec}.{tsx,ts} : Mock external dependencies and APIs in tests
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:31:52.993Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-12-30T14:31:52.993Z
Learning: Applies to **/__tests__/**/*.{test,spec}.{ts,tsx,js,jsx}|**/*.{test,spec}.{ts,tsx,js,jsx} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` files. Mock external dependencies and APIs in tests.
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:32:37.293Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.293Z
Learning: Applies to __tests__/**/__mocks__/**/*.{ts,tsx,js} : Jest automatically picks up mocks from `__mocks__` directory
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:32:37.293Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.293Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Use realistic production-like data in tests
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:32:37.293Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.293Z
Learning: Applies to __tests__/**/__tests__/**/*.{ts,tsx,js} : Write one behaviour per test with clear, descriptive test names
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:32:37.293Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: __tests__/AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:37.293Z
Learning: Applies to __tests__/**/*.{tsx,jsx},!**/__tests__/**,!**/__mocks__/** : Use semantic HTML (`<label>`, `<output>`) over ARIA attributes when possible
Applied to files:
__tests__/components/distribution/Distribution.test.tsx
📚 Learning: 2025-12-30T14:32:19.339Z
Learnt from: CR
Repo: 6529-Collections/6529seize-frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-30T14:32:19.339Z
Learning: Applies to **/{__tests__,*.test.{tsx,ts}} : Place tests in `__tests__/` directory or as `ComponentName.test.tsx` alongside the component
Applied to files:
__tests__/components/distribution/Distribution.test.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 (1)
__tests__/components/distribution/Distribution.test.tsx (1)
185-772: Excellent test organization and coverage.The test suite demonstrates strong testing practices:
- Well-organized into logical describe blocks
- Each test focuses on a single behavior
- Proper async handling with
waitFor- Comprehensive coverage of component functionality including edge cases
- Effective use of mocks and test data
- Proper cleanup with
beforeEachThe overall structure and approach align well with testing best practices and the project's testing guidelines.
Based on learnings: Tests follow the principle of one behavior per test with clear, descriptive names and use realistic production-like data.
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
185-202: Consider adding confirmation for destructive actions.The "Reset Subscriptions" button now triggers the action directly without user confirmation. Since this is a destructive operation that could result in data loss, consider adding a simple confirmation dialog (e.g.,
window.confirm()or a lightweight modal) to prevent accidental resets.🔎 Minimal confirmation example
<button onClick={() => - distributionPlan && - resetSubscriptions(contract, confirmedTokenId, distributionPlan.id) + distributionPlan && + window.confirm("Are you sure you want to reset subscriptions? This action cannot be undone.") && + resetSubscriptions(contract, confirmedTokenId, distributionPlan.id) } disabled={isResetting}openapi.yaml (3)
329-518: Distribution photo upload endpoints look consistent; consider adding 403 for Subscription Admin authorization failuresThe new
/distribution_photos/{contract}/{nft_id}/...endpoints nicely mirror the existingdrop-media/wave-mediamultipart flows and reuse shared request/response schemas, which is good for consistency.One detail: the descriptions say these require a Subscription Admin, but the responses only document
401(Unauthorized) and not403(Forbidden). Other Subscription Admin–only APIs (e.g./distributions/{contract}/{id}/overview) use403for role failures. It would be clearer for clients if the photo upload endpoints also declared a403response for “authenticated but not Subscription Admin” cases.Consider adding a
403response (e.g."Forbidden - not a Subscription Admin") to all five distribution_photos upload endpoints, or otherwise aligning their documented auth error codes with your existing Subscription Admin endpoints.
9118-9139: Clarifyautomatic_airdrops_addressesnaming to reflect it is a countIn
DistributionOverview, the field:
automatic_airdrops_addressesis typed as anintegerand described as “Count of unique addresses with automatic airdrops”.The name reads like it might be an array of addresses, but it is actually a count. If it’s still easy to change, consider renaming to something like
automatic_airdrops_addresses_count(or similar) to better match the type and description and avoid confusion for API consumers.If renaming would be too disruptive, an alternative is to emphasize in the description that this is a numeric count, not a list.
9186-9216: Photo completion request/response models look good; consider minor tightening of constraintsThe
DistributionPhotoCompleteRequest*andDistributionPhotoCompleteResponseschemas correctly model:
- A non‑empty list of photos to save (
photoswithminItems: 1) usingmedia_urlstrings.- A response with
successand the resulting list of photo URLs.Two minor, optional refinements you might consider:
- Add
format: uri(and possibly amaxLength) tomedia_urland the responsephotositems, to align with how other URL fields are constrained (e.g.ApiDropMedia.url).- Optionally add
minItems: 1toDistributionPhotoCompleteResponse.photosif you expect that successful completion always returns at least one saved photo.These aren’t required for correctness but would make the contract a bit more precise.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
generated/models/DistributionOverview.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**
📒 Files selected for processing (2)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsxopenapi.yaml
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Do not include any comments in the code; it should be self-explanatory
Write correct, up-to-date, bug-free, fully componentized, secure, and efficient code
Include all required imports and ensure proper naming of key components
Use NextJS features that match the current version
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects. If the Effect's only job is to derive or sync internal state, calculate during render or useuseMemoinstead.
UseuseEffectEventfor non-reactive logic inside Effects to read the latest props/state without turning them into dependencies or causing unnecessary re-runs.
Use explicit caching with"use cache"directive at the top of Server Components, routes, or functions. ConfigurecacheComponents: trueinnext.config.tsas needed.
**/*.{ts,tsx,js,jsx}: Remove unnecessary Effects; if the Effect only derives state, compute during render instead
UseuseEffectEventwhen listening to external events but needing the latest props/state without re-running the Effect
Move data fetching from client Effects to Server Components; mutations go through Server Actions ('use server')
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,jsx}: Use FontAwesome for icons in React components
Use TailwindCSS for styling in React components
Use react-query for data fetching
Always addreadonlybefore props in React components
**/*.{tsx,jsx}: Use internal links via<Link>component from Next.js instead of<a>tags
Replace<img>elements with<Image />fromnext/image
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Run
npm run lintto ensure code satisfies ESLint (Next's Core Web Vitals + React Hooks). Code must pass linting before completing any task.
**/*.{js,ts,jsx,tsx}: Code must satisfy ESLint with Next's Core Web Vitals and React Hooks rules by runningnpm run lint
Do not addeslint-disablecomments unless explicitly instructed; prefer refactors aligned with React 19.2, React Compiler, and Next.js 16 conventions
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
**/*.{jsx,tsx}: Replace<img>elements with<Image />fromnext/imageto comply with Next.js ESLint rule@next/next/no-img-element.
Use<Link href="/path">from Next.js for internal navigation instead of raw<a>tags to comply with@next/next/no-html-link-for-pages.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (GEMINI.md)
Use TypeScript with React functional components and hooks. Follow existing code style and naming conventions.
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with React functional components and hooks
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Prefer direct named imports from React (
useMemo,useRef,FC) overReact.namespace usage
Files:
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
🧬 Code graph analysis (1)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
services/distribution/distributionPhotoUpload.ts (1)
uploadDistributionPhotos(85-133)
⏰ 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 (11)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (9)
1-16: LGTM!Imports are clean and follow the coding guidelines with named imports from React. The refactored service import for
uploadDistributionPhotosproperly centralizes the upload logic.
17-25: LGTM!Clean error normalization helper with proper type narrowing. Defined outside the component to avoid recreation on each render.
42-61: LGTM!The
refreshOverviewcallback is correctly memoized with an empty dependency array since React guarantees setState functions are stable across renders.
63-75: LGTM!The effect correctly synchronizes with external state changes and has complete dependencies. The early returns provide clear guard clauses.
86-111: LGTM!Well-structured async function with proper loading state management and error handling using the
getErrorMessagehelper.
113-148: LGTM!The function properly handles both API-level failures (via
response.success) and network/unexpected errors (via catch block). Loading state is correctly managed in the finally block.
259-284: LGTM!The finalize button properly manages loading state and displays the current normalization status. Since finalization is typically an idempotent operation, the direct action without confirmation is reasonable here.
299-326: LGTM!Clean integration with the
uploadDistributionPhotosservice. The handler properly manages UI state, provides user feedback via toast, and uses consistent error handling.
333-375: LGTM!Consistent error handling pattern with the other handlers. The API response structure is properly typed and both success and failure paths are handled appropriately.
openapi.yaml (2)
577-608: Distribution overview endpoint is well-shaped and consistentThe new
GET /distributions/{contract}/{id}/overviewendpoint is straightforward, uses clear parameter descriptions, and returns the dedicatedDistributionOverviewschema. The documented400and403outcomes match the “Subscription Admin” requirement and are consistent with similar endpoints. No issues from the spec side here.
6036-6038: Check thatApiDropMetadata.data_valuemaxLength=5000 matches backend and UI constraintsRaising
data_value’smaxLengthto5000broadens what clients are allowed to send according to the spec. That’s fine as long as the underlying storage/validation (DB column length, server-side validators, and any front-end limits) are aligned; otherwise the OpenAPI may advertise values the backend will silently truncate or reject.Please double‑check that your persistence and validation layers accept up to 5000 characters for this field, or adjust the documented maxLength accordingly.
Signed-off-by: prxt6529 <prxt@6529.io>



Summary by CodeRabbit
New Features
Improvements
Tests
✏️ Tip: You can customize this high-level summary in your review settings.