Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughRefactors airdrops to per-phase artist/team flows with CSV upload/download (staged auth), adds minting-claims API endpoints and client helpers with per-action toggles in DropForge UI, updates OpenAPI, adds tests, textarea auto-resize, and a testnet contract constant. Changes
Sequence Diagram(s)sequenceDiagram
participant AdminUI as Admin UI (Client)
participant Auth as StagingAuth / JWT
participant API as Backend API
participant Downloader as useDownloader
AdminUI->>Auth: request staging auth / JWT
Auth-->>AdminUI: return x-6529-auth / Authorization
AdminUI->>API: GET /minting-claims/... (Authorization)
API-->>AdminUI: return action types / actions
AdminUI->>API: GET /distributions/.../artist-airdrops (Authorization)
API-->>AdminUI: return CSV URL / metadata
AdminUI->>Downloader: download(url, filename, headers)
Downloader-->>AdminUI: success / error
AdminUI->>AdminUI: update UI state or show toast on error
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
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: 4
🧹 Nitpick comments (3)
components/drop-forge/drop-forge-config.ts (1)
8-10: Remove the retired address comment block from code.Keeping old contract addresses commented in-source tends to drift and confuse future updates. Prefer commit history/release notes (or a dedicated deployment doc) for legacy references.
Suggested cleanup
-// 6529Deployer contract -// const DROP_FORGE_TESTNET_CONTRACT = -// "0xb84170c1073c7292ed108c3f0d1d2a1f304caa2c"; - // prxt contract const DROP_FORGE_TESTNET_CONTRACT = "0xb491971ba9d757d1b16feba1a019b60d6b74dc20";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/drop-forge-config.ts` around lines 8 - 10, Remove the retired contract address comment block that references the old 6529Deployer address (the commented DROP_FORGE_TESTNET_CONTRACT block) from drop-forge-config.ts to avoid confusion; simply delete the three-line commented address and any trailing blank lines so the file contains only current config/constants and rely on git history for legacy references.openapi.yaml (1)
9216-9219: Enforce uniqueness for action name arrays.Line 9216-9219 (
actions) and Line 9229-9233 (action_types) represent key-like action identifiers; allowing duplicates can create ambiguous UI state and duplicate toggles. ConsideruniqueItems: trueon both arrays.♻️ Suggested update
actions: type: array + uniqueItems: true items: $ref: "#/components/schemas/ApiMintingClaimAction" action_types: type: array + uniqueItems: true items: type: string minLength: 1 description: Contract-specific minting claim action nameAlso applies to: 9229-9233
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 9216 - 9219, The arrays named actions and action_types in the OpenAPI schema allow duplicate entries which can cause ambiguous UI state; update the schema definitions that reference "actions" (items: $ref: "#/components/schemas/ApiMintingClaimAction") and "action_types" to include uniqueItems: true so each array enforces uniqueness (i.e., add uniqueItems: true to those array schema objects).components/waves/memes/submission/details/ArtworkDetails.tsx (1)
81-94: This puts the parent form reducer back on the keystroke hot path.These handlers now fire
onTitleChange/onDescriptionChangeon every input event, and the parent callbacks immediately dispatch form-state updates. That largely cancels out the uncontrolled-input optimization in this component; if you only need live local UI feedback, keep that local and debounce or blur-commit the parent update instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/waves/memes/submission/details/ArtworkDetails.tsx` around lines 81 - 94, handleTitleInput and handleDescriptionInput call onTitleChange/onDescriptionChange on every keystroke which defeats the component's uncontrolled-input optimization; instead, keep input value locally and only notify the parent on a debounced commit or onBlur. Change handleTitleInput/handleDescriptionInput to update local state (e.g., titleLocal/descriptionLocal), continue to call resizeDescriptionTextarea(event.currentTarget) for UI sizing, and invoke onTitleChange/onDescriptionChange only from a debounced function or from a new onBlur handler to commit the value to the parent; ensure initial prop -> local state sync and cleanup for any debouncer.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx`:
- Around line 664-668: Clear the stale overview before starting a refresh and
ignore out-of-order responses: update refreshOverview() to set the overview
state to null/undefined immediately when invoked (so
isAutomaticAirdropsDownloadDisabled uses the cleared state), capture the current
token identifier or a monotonic requestId at call time, and when the async
response resolves verify the captured tokenId/requestId still matches before
calling the overview setter; also ensure any token-switch handler clears
overview the same way so the footer never reads the previous token’s counts.
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 881-893: The mapping for section.phaseKey misses phase2 so
actionName becomes null; update the conditional that sets actionName in
DropForgeLaunchClaimPageClient.view.tsx to include a branch for section.phaseKey
=== "phase2" -> "PHASE2_AIRDROP" so that action =
mintingClaimActionsByName[actionName] resolves for phase2 and the completion
toggle and disabled state work correctly (ensure you update the same expression
that computes actionName and that downstream uses of action remain unchanged).
- Around line 719-730: The completion Toggle in
DropForgeLaunchClaimPageClient.view.tsx is only disabled by actionPending and
remains clickable while a claim transaction is in-flight (claimWritePending),
risking state drift if the tx reverts; update the Toggle's disabled prop (the
Toggle rendering around action.completed) to use the same combined in-flight
guard as the action button (include claimWritePending alongside actionPending or
reuse the shared boolean used by the action button), and apply the identical
guard to the inline subscription and research Toggle controls later in the file
so all toggles are disabled while any related on-chain write is unresolved.
In `@openapi.yaml`:
- Around line 9211-9215: The response schema currently defines "contract" as a
generic string and "claim_id" as an unconstrained int64; update the schema for
the "contract" property to match the path param Ethereum-address validation
(e.g. require minLength 42 and a regex pattern like ^0x[a-fA-F0-9]{40}$) and
make "claim_id" non-negative (e.g. minimum: 0 with format: int64) so response
shapes mirror input validation; apply the same changes to the other occurrence
noted (the second "contract"/"claim_id" block).
---
Nitpick comments:
In `@components/drop-forge/drop-forge-config.ts`:
- Around line 8-10: Remove the retired contract address comment block that
references the old 6529Deployer address (the commented
DROP_FORGE_TESTNET_CONTRACT block) from drop-forge-config.ts to avoid confusion;
simply delete the three-line commented address and any trailing blank lines so
the file contains only current config/constants and rely on git history for
legacy references.
In `@components/waves/memes/submission/details/ArtworkDetails.tsx`:
- Around line 81-94: handleTitleInput and handleDescriptionInput call
onTitleChange/onDescriptionChange on every keystroke which defeats the
component's uncontrolled-input optimization; instead, keep input value locally
and only notify the parent on a debounced commit or onBlur. Change
handleTitleInput/handleDescriptionInput to update local state (e.g.,
titleLocal/descriptionLocal), continue to call
resizeDescriptionTextarea(event.currentTarget) for UI sizing, and invoke
onTitleChange/onDescriptionChange only from a debounced function or from a new
onBlur handler to commit the value to the parent; ensure initial prop -> local
state sync and cleanup for any debouncer.
In `@openapi.yaml`:
- Around line 9216-9219: The arrays named actions and action_types in the
OpenAPI schema allow duplicate entries which can cause ambiguous UI state;
update the schema definitions that reference "actions" (items: $ref:
"#/components/schemas/ApiMintingClaimAction") and "action_types" to include
uniqueItems: true so each array enforces uniqueness (i.e., add uniqueItems: true
to those array schema objects).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1e52928a-9b5a-42cb-a514-7f828d6de063
⛔ Files ignored due to path filters (5)
generated/models/ApiMintingClaimAction.tsis excluded by!**/generated/**generated/models/ApiMintingClaimActionTypesResponse.tsis excluded by!**/generated/**generated/models/ApiMintingClaimActionUpdateRequest.tsis excluded by!**/generated/**generated/models/ApiMintingClaimActionsResponse.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**
📒 Files selected for processing (9)
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/services/api/memes-minting-claims-api.test.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsxcomponents/drop-forge/drop-forge-config.tscomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsxcomponents/waves/memes/submission/details/ArtworkDetails.tsxopenapi.yamlservices/api/memes-minting-claims-api.ts
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
__tests__/services/api/memes-minting-claims-api.test.ts (1)
27-34: Consider extracting a small helper for repeated successful fetch mocks.This would reduce duplication and make future additions easier to read.
♻️ Optional refactor
+const mockOkJson = <T>(payload: T) => { + fetchMock.mockResolvedValue({ + ok: true, + json: async () => payload, + } as Response); +}; - fetchMock.mockResolvedValue({ - ok: true, - json: async () => ({ - contract: MEMES_CONTRACT, - action_types: ["ARTIST_AIRDROP", "TEAM_AIRDROP"], - }), - }); + mockOkJson({ + contract: MEMES_CONTRACT, + action_types: ["ARTIST_AIRDROP", "TEAM_AIRDROP"], + });Also applies to: 48-55, 71-78
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@__tests__/services/api/memes-minting-claims-api.test.ts` around lines 27 - 34, Tests repeatedly call fetchMock.mockResolvedValue with the same successful response shape; extract a small helper (e.g., mockFetchOk or mockedFetchResponse) to return the { ok: true, json: async () => ({ contract: MEMES_CONTRACT, action_types: [...] }) } object and use it in the tests that assert supported MEMES claim action types (the fetchMock.mockResolvedValue calls in __tests__/services/api/memes-minting-claims-api.test.ts used in the "fetches supported MEMES claim action types" and the other two similar cases). Update the three repeated blocks to call the helper with the specific action_types array for each case so the tests remain identical but with less duplication.components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx (1)
630-642: Add a defensive re-entry guard in the download handler.Relying only on button disabled state can still allow duplicate invocations in edge timing scenarios. A local early-return makes this path safer.
♻️ Suggested patch
const handleDownloadAutomaticAirdrops = useCallback( async (contract: string, tokenId: string) => { + if (isDownloadingAutomaticAirdrops) { + return; + } await downloadAutomaticAirdropsCsv( `${publicEnv.API_ENDPOINT}/api/distributions/${contract}/${tokenId}/automatic_airdrops`, `automatic_airdrops_${tokenId}.csv`, undefined, { headers: buildAutomaticAirdropsDownloadHeaders(), } ); }, - [buildAutomaticAirdropsDownloadHeaders, downloadAutomaticAirdropsCsv] + [ + buildAutomaticAirdropsDownloadHeaders, + downloadAutomaticAirdropsCsv, + isDownloadingAutomaticAirdrops, + ] );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx` around lines 630 - 642, The handler handleDownloadAutomaticAirdrops lacks a defensive re-entry guard, so add a local guard (e.g., isDownloading ref or state) to prevent concurrent invocations: at the top of handleDownloadAutomaticAirdrops return early if the guard is set, set the guard true before calling downloadAutomaticAirdropsCsv, and clear it in a finally block so it always resets after await (including on errors); reference the existing symbols handleDownloadAutomaticAirdrops, downloadAutomaticAirdropsCsv, and buildAutomaticAirdropsDownloadHeaders when making the change.components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx (1)
247-276: Prefer exact alias matching before substring scoring.The heuristic matcher is flexible, but it can pick the wrong action when names overlap (e.g., future similarly-prefixed action types). Add an exact normalized alias lookup first, then keep this scoring as fallback.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx` around lines 247 - 276, In findBestMatchingMintingClaimActionName, add a fast exact normalized-alias lookup before the current substring scoring: build normalized names via normalizeMintingClaimActionName for each actionName and check for an exact match against preferred terms (then required terms) returned by getMintingClaimActionTerms(kind) — if any normalized actionName exactly equals a preferred (or required) term, immediately return that original actionName; only if no exact match is found fall back to the existing excluded/required checks and scoring logic as the secondary heuristic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx`:
- Around line 665-695: The memoized renderedMintingClaimActions currently
fabricates missing actions with completed: false even when the source
mintingClaimActions is absent (e.g., fetch failure), which can surface incorrect
UI state; change the logic so that you only generate missingActions when
mintingClaimActions (and its .actions array) is present and known-good—if
mintingClaimActions is null/undefined or .actions is missing, return an empty
array (or the raw currentActions) instead of appending synthetic
ApiMintingClaimAction entries; update the useMemo that references
mintingClaimActions, mintingClaimActionTypes, orderedActions and missingActions
to gate creation of missingActions on the existence of
mintingClaimActions/.actions.
---
Nitpick comments:
In `@__tests__/services/api/memes-minting-claims-api.test.ts`:
- Around line 27-34: Tests repeatedly call fetchMock.mockResolvedValue with the
same successful response shape; extract a small helper (e.g., mockFetchOk or
mockedFetchResponse) to return the { ok: true, json: async () => ({ contract:
MEMES_CONTRACT, action_types: [...] }) } object and use it in the tests that
assert supported MEMES claim action types (the fetchMock.mockResolvedValue calls
in __tests__/services/api/memes-minting-claims-api.test.ts used in the "fetches
supported MEMES claim action types" and the other two similar cases). Update the
three repeated blocks to call the helper with the specific action_types array
for each case so the tests remain identical but with less duplication.
In
`@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx`:
- Around line 630-642: The handler handleDownloadAutomaticAirdrops lacks a
defensive re-entry guard, so add a local guard (e.g., isDownloading ref or
state) to prevent concurrent invocations: at the top of
handleDownloadAutomaticAirdrops return early if the guard is set, set the guard
true before calling downloadAutomaticAirdropsCsv, and clear it in a finally
block so it always resets after await (including on errors); reference the
existing symbols handleDownloadAutomaticAirdrops, downloadAutomaticAirdropsCsv,
and buildAutomaticAirdropsDownloadHeaders when making the change.
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 247-276: In findBestMatchingMintingClaimActionName, add a fast
exact normalized-alias lookup before the current substring scoring: build
normalized names via normalizeMintingClaimActionName for each actionName and
check for an exact match against preferred terms (then required terms) returned
by getMintingClaimActionTerms(kind) — if any normalized actionName exactly
equals a preferred (or required) term, immediately return that original
actionName; only if no exact match is found fall back to the existing
excluded/required checks and scoring logic as the secondary heuristic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d04b64cd-df6c-40ae-b7b3-a89a50d79cfc
📒 Files selected for processing (5)
__tests__/services/api/memes-minting-claims-api.test.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsxcomponents/drop-forge/drop-forge-config.tscomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- components/drop-forge/drop-forge-config.ts
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx (1)
665-695:⚠️ Potential issue | 🟠 MajorAvoid synthesizing
completed: falseactions when action status payload is unavailable.At Line 671 and Lines 684-692, when
mintingClaimActionsis missing (e.g., fetch failure), the memo still fabricates all supported actions as incomplete. This can surface stale state and re-enable actions incorrectly.Suggested fix
const renderedMintingClaimActions = useMemo<ApiMintingClaimAction[]>(() => { - if (!mintingClaimActionTypes || mintingClaimActionTypes.length === 0) { + if ( + !mintingClaimActionTypes || + mintingClaimActionTypes.length === 0 || + !mintingClaimActions?.actions + ) { return []; } const supportedTypes = new Set(mintingClaimActionTypes); - const currentActions = mintingClaimActions?.actions ?? []; + const currentActions = mintingClaimActions.actions;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx` around lines 665 - 695, The memo currently fabricates missing actions with completed: false even when the server payload is absent; update renderedMintingClaimActions so it first guards on mintingClaimActions (the object, not just its .actions): if mintingClaimActions is null/undefined return [] immediately and do not build missingActions from mintingClaimActionTypes; otherwise proceed to compute orderedActions and only derive missingActions when mintingClaimActions exists (producing ApiMintingClaimAction entries from actual payload), ensuring references to renderedMintingClaimActions, mintingClaimActions, mintingClaimActionTypes, and ApiMintingClaimAction are used to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 847-850: The button disable logic currently uses "disabled ||
isCompleted" but omits the pending state, allowing duplicate clicks while a
minting action is in flight; update the three button elements in
DropForgeLaunchClaimPageClient.view.tsx (the buttons using props disabled,
isCompleted and onClick) to also include the "mintingClaimActionPending" flag in
their disabled expression (e.g., disabled || isCompleted ||
mintingClaimActionPending) so the buttons are blocked while
mintingClaimActionPending is true; ensure the same change is applied to every
button occurrence that uses the disabled/isCompleted logic (the ones around the
onClick handlers referenced) so all duplicate-click race windows are closed.
---
Duplicate comments:
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx`:
- Around line 665-695: The memo currently fabricates missing actions with
completed: false even when the server payload is absent; update
renderedMintingClaimActions so it first guards on mintingClaimActions (the
object, not just its .actions): if mintingClaimActions is null/undefined return
[] immediately and do not build missingActions from mintingClaimActionTypes;
otherwise proceed to compute orderedActions and only derive missingActions when
mintingClaimActions exists (producing ApiMintingClaimAction entries from actual
payload), ensuring references to renderedMintingClaimActions,
mintingClaimActions, mintingClaimActionTypes, and ApiMintingClaimAction are used
to locate the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c6ec104e-2482-48b1-a1fe-a87d9072483b
📒 Files selected for processing (2)
components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx (1)
847-850:⚠️ Potential issue | 🟠 MajorDisable the airdrop buttons while action-status updates are pending.
Lines 849, 1053, and 1213 still ignore
mintingClaimActionPending. That means a user can flip a completion toggle and immediately fire the corresponding airdrop before the backend update settles, leaving the action trail out of sync if the transaction later fails.🔒 Reuse the same pending guard on the buttons
- disabled={disabled || isCompleted} + disabled={disabled || isCompleted || actionPending !== null}disabled={ !isInitialized || claimWritePending || + mintingClaimActionPending !== null || section.loading || section.airdropCount <= 0 || (action?.completed ?? false) }disabled={ claimWritePending || + mintingClaimActionPending !== null || !isInitialized || researchAirdropCount <= 0 || isCompleted }Also applies to: 1051-1059, 1211-1218
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx` around lines 847 - 850, The buttons that trigger airdrops (the <button> elements using props like disabled, isCompleted and onClick) do not include the global mintingClaimActionPending guard, allowing actions while backend status updates are in-flight; update each button (references around where disabled={disabled || isCompleted} is set — e.g., the button at lines near 847, 1053, 1213) to also disable when mintingClaimActionPending is true (disabled={disabled || isCompleted || mintingClaimActionPending}) so clicks are ignored while the claim action update is pending; ensure any handlers that read/modify action state (onClick callbacks) are unchanged but cannot be invoked when mintingClaimActionPending is set.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx`:
- Around line 1043-1089: In updateMintingClaimAction, guard against stale
responses by capturing the active claimId into a local variable (e.g., const
currentClaimId = claimId) before any await (specifically before calling
upsertMemesMintingClaimAction) and after each await verify that claimId is still
equal to currentClaimId; if it has changed, return early and do not call
setMintingClaimActions or mutate pending state. Also apply the same check in the
finally block so setMintingClaimActionPending only clears the pending action
when the claimId still matches the captured currentClaimId.
---
Duplicate comments:
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 847-850: The buttons that trigger airdrops (the <button> elements
using props like disabled, isCompleted and onClick) do not include the global
mintingClaimActionPending guard, allowing actions while backend status updates
are in-flight; update each button (references around where disabled={disabled ||
isCompleted} is set — e.g., the button at lines near 847, 1053, 1213) to also
disable when mintingClaimActionPending is true (disabled={disabled ||
isCompleted || mintingClaimActionPending}) so clicks are ignored while the claim
action update is pending; ensure any handlers that read/modify action state
(onClick callbacks) are unchanged but cannot be invoked when
mintingClaimActionPending is set.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f1cf4bd0-528c-4190-b2e6-ee86595b7f06
📒 Files selected for processing (4)
__tests__/services/api/memes-minting-claims-api.test.tscomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/services/api/memes-minting-claims-api.test.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
Actionable comments posted: 6
♻️ Duplicate comments (1)
openapi.yaml (1)
9378-9401:⚠️ Potential issue | 🟠 MajorResponse schema constraints still don’t mirror validated inputs.
contractremains unconstrained andclaim_idis not bounded in response schemas, while path params enforce stricter validation. This weakens generated client validation.Suggested schema alignment
ApiMintingClaimActionsResponse: type: object required: - contract - claim_id - actions properties: contract: - type: string + $ref: "#/components/schemas/ApiEthereumAddress" claim_id: type: integer format: int64 + minimum: 1 ApiMintingClaimActionTypesResponse: type: object required: - contract - action_types properties: contract: - type: string + $ref: "#/components/schemas/ApiEthereumAddress"🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 9378 - 9401, The response schemas ApiMintingClaimActionsResponse and ApiMintingClaimActionTypesResponse currently leave contract and claim_id unconstrained; update these schema properties to mirror the input/path param validations (e.g., add the same contract pattern/enum and the same numeric bounds on claim_id such as format: int64 plus minimum/maximum values used for the path param validation) so generated clients will enforce the same constraints; modify the properties named contract and claim_id in ApiMintingClaimActionsResponse and the contract and action_types definitions in ApiMintingClaimActionTypesResponse to include those validation keywords (pattern/enum/minimum/maximum) that match the existing path parameter rules.
🧹 Nitpick comments (3)
__tests__/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts (1)
117-128: Add a regression case for non-phase0null schedule.Current coverage only checks null schedule on
phase0. Add a case where a later phase hasschedule: nulland verify selection still follows available schedules.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@__tests__/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts` around lines 117 - 128, Add a regression test that verifies getAutoSelectedLaunchPhase correctly ignores a null schedule on a non-phase0 entry: create a new it(...) similar to the existing "falls back to phase0 when phase0's schedule is null" but set schedule: null on a later phase (e.g., index 1 or 2) using phases.map and ensure the returned value is the expected phase with a valid schedule (call getAutoSelectedLaunchPhase with hasPublishedMetadata: true, isInitialized: true, nowMs matching the test scenario and assert the selected phase string). Reference getAutoSelectedLaunchPhase and the phases test fixture to locate where to add this case.openapi.yaml (1)
12230-12245: Consider non-negative bounds for distribution counters.These are counts and should be explicitly non-negative in the schema.
Suggested constraint hardening
artist_airdrops_addresses: type: integer format: int64 + minimum: 0 artist_airdrops_count: type: integer format: int64 + minimum: 0 team_airdrops_addresses: type: integer format: int64 + minimum: 0 team_airdrops_count: type: integer format: int64 + minimum: 0🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openapi.yaml` around lines 12230 - 12245, The schema properties artist_airdrops_addresses, artist_airdrops_count, team_airdrops_addresses, and team_airdrops_count represent counts and must be constrained to non-negative values; update each property in the OpenAPI schema to include a minimum: 0 (and optionally exclusiveMinimum: false) so the validator enforces they cannot be negative while keeping the existing type/format/description intact.components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx (1)
828-835: Simplify toggle callback by passing the next checked state directly.At lines 834, 1035, and 1187, the callbacks pass
action.completed(current state) and rely onhandleMintingClaimActionToggle(line 1147) to invert it with!completedbefore sending to the API. While this works correctly, it adds unnecessary indirection. Passinge.target.checkeddirectly would make the intent explicit and reduce cognitive load:Suggested refactoring
- onChange={() => { - void onActionToggle(action.action, action.completed); - }} + onChange={(e) => { + void onActionToggle(action.action, e.target.checked); + }}- onChange={() => { - void onMintingClaimActionToggle( - action.action, - action.completed - ); - }} + onChange={(e) => { + void onMintingClaimActionToggle( + action.action, + e.target.checked + ); + }}- onChange={() => { - void onMintingClaimActionToggle( - researchAction.action, - researchAction.completed - ); - }} + onChange={(e) => { + void onMintingClaimActionToggle( + researchAction.action, + e.target.checked + ); + }}Then remove the inversion in
handleMintingClaimActionToggle(line 1150):const handleMintingClaimActionToggle = useCallback( async (action: string, completed: boolean) => { await updateMintingClaimAction({ action, - completed: !completed, + completed, }); }, [updateMintingClaimAction] );Also applies to: 1029–1038, 1181–1190
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx` around lines 828 - 835, The Toggle onChange callbacks should pass the next checked state from the event instead of the current action.completed and letting handleMintingClaimActionToggle invert it; update all Toggle usages (the Toggle with props checked={action.completed} and onChange={() => void onActionToggle(action.action, action.completed)} as well as the other occurrences) to call onActionToggle(action.action, e.target.checked) (or the equivalent second-arg boolean from the change event), and then adjust handleMintingClaimActionToggle (and any callers expecting inverted logic) to accept the new boolean as the desired completed state (remove the internal !completed inversion) so the value sent to the API is the explicit checked state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx`:
- Around line 708-723: handleDownloadAirdrops currently only uses a finally
block so rejected downloads reset state but produce no user-facing error; add an
explicit catch on the promise from downloadAirdropsCsv to call the app toast
(e.g. toast.error) with a clear message (include the phase/tokenId) and
optionally console.error the error, then rethrow or swallow as appropriate,
keeping the existing finally that resets isDownloadingAirdropsRef.current and
setDownloadingAirdropsPhase(null); reference the handleDownloadAirdrops
function, downloadAirdropsCsv call, buildAirdropsDownloadHeaders,
isDownloadingAirdropsRef and setDownloadingAirdropsPhase when making the change.
In `@components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.ts`:
- Around line 207-209: The current guard returns "phase0" if any phase lacks a
schedule, causing unwanted fallback when only some phases (e.g., publicphase)
are missing; change the condition in the if block that checks phases to only
fallback when there are no phases OR when all phases lack schedules (use
phases.every(phase => !phase.schedule) instead of phases.some(...)). Update the
if that returns "phase0" to: if (phases.length === 0 || phases.every((phase) =>
!phase.schedule)) { return "phase0"; } to avoid jumping back to phase0 on
partial schedule gaps.
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx`:
- Around line 82-89: Add an explicit mapping for the missing PHASE2_AIRDROP key
in the MEMES_MINTING_CLAIM_ACTION_LABELS record so the UI uses the correct label
text; specifically update the MEMES_MINTING_CLAIM_ACTION_LABELS constant to
include PHASE2_AIRDROP: "Phase 2 Airdrop" (refer to the
MEMES_MINTING_CLAIM_ACTION_LABELS constant and the PHASE2_AIRDROP key) to avoid
the fallback formatting inconsistency.
In `@openapi.yaml`:
- Around line 819-823: The operation descriptions currently imply the request
body is raw CSV but the schema expects a JSON object with a csv field; update
the description for this endpoint (and the other instances noted: the blocks
around lines 842-844, 901-905, 923-925) to explicitly state that the request
body is a JSON object with a property named "csv" whose value is the CSV text in
"address,count" format, and adjust any examples or exampleMediaType to show the
JSON wrapper rather than raw CSV so generated clients and docs reflect the true
contract.
- Around line 9403-9407: The array schema for action_types should enforce the
same string pattern used by ApiMintingClaimAction.action and
ApiMintingClaimActionUpdateRequest.action; update the items schema for
action_types to include the identical pattern (regex) constraint (in addition to
minLength: 1) so each entry validates against the same allowed action name
format as ApiMintingClaimAction.action and
ApiMintingClaimActionUpdateRequest.action.
- Around line 9093-9096: The schema example for last_date uses a locale-specific
string ("12.03.2026"); update the OpenAPI schema for the last_date property to
use an unambiguous ISO format and/or a formal OpenAPI date type: change or
augment last_date to type: string with format: date (or format: date-time if
time is needed) and replace the example with an ISO value like "2026-03-12" (or
"2026-03-12T00:00:00Z"), or add a regex pattern to enforce the ISO format; refer
to the last_date property in the OpenAPI schema when making this change.
---
Duplicate comments:
In `@openapi.yaml`:
- Around line 9378-9401: The response schemas ApiMintingClaimActionsResponse and
ApiMintingClaimActionTypesResponse currently leave contract and claim_id
unconstrained; update these schema properties to mirror the input/path param
validations (e.g., add the same contract pattern/enum and the same numeric
bounds on claim_id such as format: int64 plus minimum/maximum values used for
the path param validation) so generated clients will enforce the same
constraints; modify the properties named contract and claim_id in
ApiMintingClaimActionsResponse and the contract and action_types definitions in
ApiMintingClaimActionTypesResponse to include those validation keywords
(pattern/enum/minimum/maximum) that match the existing path parameter rules.
---
Nitpick comments:
In
`@__tests__/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts`:
- Around line 117-128: Add a regression test that verifies
getAutoSelectedLaunchPhase correctly ignores a null schedule on a non-phase0
entry: create a new it(...) similar to the existing "falls back to phase0 when
phase0's schedule is null" but set schedule: null on a later phase (e.g., index
1 or 2) using phases.map and ensure the returned value is the expected phase
with a valid schedule (call getAutoSelectedLaunchPhase with
hasPublishedMetadata: true, isInitialized: true, nowMs matching the test
scenario and assert the selected phase string). Reference
getAutoSelectedLaunchPhase and the phases test fixture to locate where to add
this case.
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 828-835: The Toggle onChange callbacks should pass the next
checked state from the event instead of the current action.completed and letting
handleMintingClaimActionToggle invert it; update all Toggle usages (the Toggle
with props checked={action.completed} and onChange={() => void
onActionToggle(action.action, action.completed)} as well as the other
occurrences) to call onActionToggle(action.action, e.target.checked) (or the
equivalent second-arg boolean from the change event), and then adjust
handleMintingClaimActionToggle (and any callers expecting inverted logic) to
accept the new boolean as the desired completed state (remove the internal
!completed inversion) so the value sent to the API is the explicit checked
state.
In `@openapi.yaml`:
- Around line 12230-12245: The schema properties artist_airdrops_addresses,
artist_airdrops_count, team_airdrops_addresses, and team_airdrops_count
represent counts and must be constrained to non-negative values; update each
property in the OpenAPI schema to include a minimum: 0 (and optionally
exclusiveMinimum: false) so the validator enforces they cannot be negative while
keeping the existing type/format/description intact.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: cf39d1b1-03c7-47e0-87ae-ce438374cfbe
⛔ Files ignored due to path filters (6)
generated/models/ApiDistributionAirdropsCsvUploadRequest.tsis excluded by!**/generated/**generated/models/ApiDistributionAirdropsUploadResponse.tsis excluded by!**/generated/**generated/models/ApiDropWinningContext.tsis excluded by!**/generated/**generated/models/ApiIdentityActivity.tsis excluded by!**/generated/**generated/models/DistributionOverview.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**
📒 Files selected for processing (13)
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts__tests__/services/api/memes-minting-claims-api.test.tscomponents/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/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsxcomponents/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.tsopenapi.yamlservices/api/memes-minting-claims-api.ts
💤 Files with no reviewable changes (1)
- components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/services/api/memes-minting-claims-api.test.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
There was a problem hiding this comment.
🧹 Nitpick comments (3)
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx (1)
117-120: Consider using non-null assertion for consistency.The optional chaining
numbers[0]?.toString()differs from the pattern inUploadDistributionPhotosModal(line 23 usesnumbers[0]!.toString()). While both should work correctly given thatextractAllNumbersreturns actual numbers, using consistent patterns across similar components improves maintainability.♻️ Suggested alignment with existing pattern
const numbers = extractAllNumbers(props.plan.name); - const initialTokenId = numbers.length > 0 ? numbers[0]?.toString() : ""; - const defaultTokenId = isValidPositiveInteger(initialTokenId!) - ? initialTokenId! + const initialTokenId = numbers.length > 0 ? numbers[0]!.toString() : ""; + const defaultTokenId = isValidPositiveInteger(initialTokenId) + ? initialTokenId : "";🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx` around lines 117 - 120, The code uses optional chaining when deriving initialTokenId but the project prefers a non-null assertion for consistency: replace the expression that sets initialTokenId to use numbers[0]!.toString() instead of numbers[0]?.toString(), keeping the subsequent isValidPositiveInteger check for defaultTokenId; update the initializer of initialTokenId (and any related typings) so it uses the non-null assertion with numbers and preserves the existing logic in defaultTokenId and isValidPositiveInteger.components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx (1)
818-836: Consider includingdisabledprop in toggle guard for consistency.The toggle's
isActionToggleDisabledguards againstclaimWritePendingandactionPending, but thedisabledprop also includes!isInitialized. While!isInitializedtypically impliesclaimWritePendingwon't trigger, there's a brief window where the toggle could be clickable before full initialization. For defensive consistency with the button:♻️ Suggested guard alignment
- const isActionToggleDisabled = claimWritePending || actionPending !== null; + const isActionToggleDisabled = disabled || claimWritePending || actionPending !== null;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx` around lines 818 - 836, The Toggle can become clickable before full initialization; update the guard so the Toggle's disabled prop includes the initialization check (i.e., include !isInitialized) for defensive consistency with the button. Locate the isActionToggleDisabled/Toggle usage and either add !isInitialized into the isActionToggleDisabled expression or change the Toggle's disabled to combine isActionToggleDisabled || !isInitialized so onActionToggle cannot fire until initialized.__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx (1)
504-518: Hardcoded API URL may cause brittle tests.The test expects a specific URL
https://api.test.6529.io/api/distributions/...but doesn't explicitly mockpublicEnv.API_ENDPOINT. If the test environment's API endpoint differs, this will fail.Consider using
expect.stringContainingfor the path portion or explicitly settingpublicEnv.API_ENDPOINTin the test setup.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx` around lines 504 - 518, The test is brittle because it asserts the full hardcoded API URL when `publicEnv.API_ENDPOINT` may vary; update the expectation in the test that calls `mockDownload` (the assertion inside the `waitFor` block that uses `expect(mockDownload).toHaveBeenCalledWith`) to either explicitly set `publicEnv.API_ENDPOINT` in the test setup or replace the full-URL argument with a matcher such as `expect.stringContaining("/api/distributions/0x33FD426905F149f8376e227d0C9D3340AaD17aF1/123/artist-airdrops")` so the path is asserted while allowing the host to vary, and keep the other `toHaveBeenCalledWith` args unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx`:
- Around line 504-518: The test is brittle because it asserts the full hardcoded
API URL when `publicEnv.API_ENDPOINT` may vary; update the expectation in the
test that calls `mockDownload` (the assertion inside the `waitFor` block that
uses `expect(mockDownload).toHaveBeenCalledWith`) to either explicitly set
`publicEnv.API_ENDPOINT` in the test setup or replace the full-URL argument with
a matcher such as
`expect.stringContaining("/api/distributions/0x33FD426905F149f8376e227d0C9D3340AaD17aF1/123/artist-airdrops")`
so the path is asserted while allowing the host to vary, and keep the other
`toHaveBeenCalledWith` args unchanged.
In
`@components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx`:
- Around line 117-120: The code uses optional chaining when deriving
initialTokenId but the project prefers a non-null assertion for consistency:
replace the expression that sets initialTokenId to use numbers[0]!.toString()
instead of numbers[0]?.toString(), keeping the subsequent isValidPositiveInteger
check for defaultTokenId; update the initializer of initialTokenId (and any
related typings) so it uses the non-null assertion with numbers and preserves
the existing logic in defaultTokenId and isValidPositiveInteger.
In `@components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx`:
- Around line 818-836: The Toggle can become clickable before full
initialization; update the guard so the Toggle's disabled prop includes the
initialization check (i.e., include !isInitialized) for defensive consistency
with the button. Locate the isActionToggleDisabled/Toggle usage and either add
!isInitialized into the isActionToggleDisabled expression or change the Toggle's
disabled to combine isActionToggleDisabled || !isInitialized so onActionToggle
cannot fire until initialized.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: da197abc-3722-403a-8792-a5a8234f5ae6
⛔ Files ignored due to path filters (6)
generated/models/ApiDistributionAirdropsCsvUploadRequest.tsis excluded by!**/generated/**generated/models/ApiDistributionAirdropsUploadResponse.tsis excluded by!**/generated/**generated/models/ApiDropWinningContext.tsis excluded by!**/generated/**generated/models/ApiIdentityActivity.tsis excluded by!**/generated/**generated/models/DistributionOverview.tsis excluded by!**/generated/**generated/models/ObjectSerializer.tsis excluded by!**/generated/**
📒 Files selected for processing (13)
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx__tests__/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts__tests__/services/api/memes-minting-claims-api.test.tscomponents/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/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsxcomponents/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.tsxcomponents/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsxcomponents/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.tsopenapi.yamlservices/api/memes-minting-claims-api.ts
💤 Files with no reviewable changes (1)
- components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.test.ts
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
|



Summary by CodeRabbit
New Features
API
Tests
Bug Fixes / UX
Removals