Skip to content

Minting Claims - Actions Trail#2114

Merged
prxt6529 merged 32 commits intomainfrom
minting-claims-actions
Mar 17, 2026
Merged

Minting Claims - Actions Trail#2114
prxt6529 merged 32 commits intomainfrom
minting-claims-actions

Conversation

@prxt6529
Copy link
Copy Markdown
Collaborator

@prxt6529 prxt6529 commented Mar 13, 2026

Summary by CodeRabbit

  • New Features

    • Per-phase artist/team airdrops: CSV upload/download per phase and admin-facing minting-claim toggles; live title/description syncing with auto-resizing textarea.
  • API

    • New minting-claims endpoints and CSV-friendly artist/team airdrops endpoints; distribution overview now exposes artist/team airdrop fields.
  • Tests

    • Expanded tests for minting-claims, airdrops CSV flows, auth headers, empty states and error handling.
  • Bug Fixes / UX

    • Disable CSV download when no airdrops; surface download/upload errors via admin toast.
  • Removals

    • Removed legacy single automatic-airdrops modal; modals now rely on mount-based visibility.

Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
@prxt6529 prxt6529 changed the title Minting claims actions Minting Claims - Actions Trail Mar 13, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 13, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Refactors 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

Cohort / File(s) Summary
Distribution plan footer & phase airdrops
components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx, components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx, components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.tsx, components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsx, components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
Replaces single AutomaticAirdrops flow with per-phase (artist/team) modal component and APIs; adds buildAirdropsDownloadHeaders, staged-auth CSV download via useDownloader, per-phase upload/download state and callbacks, overview shape updates, and deletes legacy AutomaticAirdropsModal.
Footer tests & mocks
__tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx
Extends tests with mocks for downloader/auth, SeizeSettingsContext, updated overview shape (artist/team fields), new modal IDs, CSV download success/error/disabled cases, and updated upload wiring.
Minting-claims OpenAPI & client
openapi.yaml, services/api/memes-minting-claims-api.ts
Adds minting-claims endpoints and schemas (types, actions, upsert), updates distribution airdrops paths (artist/team), and implements client helpers: getMemesMintingClaimActionTypes, getMemesMintingClaimActions, upsertMemesMintingClaimAction.
Minting-claims tests
__tests__/services/api/memes-minting-claims-api.test.ts
New unit tests validating URL composition, fetch method/headers/body, and responses for types/actions/upsert endpoints with auth stubs.
DropForge — client logic
components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx, components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.ts
Loads action types/actions with auth, tracks per-action pending/completed state, adds upsert/toggle flows, integrates pending actions into airdrop/transaction lifecycle, and exports getAutoSelectedLaunchPhase helper.
DropForge — view/UI wiring
components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
Adds per-action UI toggles/indicators across launch sections, threads mintingClaimActionsByName, mintingClaimActionPending, and onMintingClaimActionToggle props; resolves best-matching action names per section.
DropForge config
components/drop-forge/drop-forge-config.ts
Adds DROP_FORGE_TESTNET_CONTRACT constant with annotated address.
Artwork details input
components/waves/memes/submission/details/ArtworkDetails.tsx
Adds resizeDescriptionTextarea, switches to onInput for immediate title/description updates, and adjusts layout/styling for inputs and icons.

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • GelatoGenesis
  • analyticsflowee

Poem

🐰 I nibble at code with a floppy-ear grin,
CSVs tumble, toggles flip, downloads begin.
Textareas stretch as fingers dance light,
Actions pend, then settle — the admin's delight.
Carrots and commits — hop, push, and win! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately reflects the main feature: adding minting claims action tracking and UI controls throughout the distribution and claim flow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch minting-claims-actions
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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. Consider uniqueItems: true on 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 name

Also 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/onDescriptionChange on 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

📥 Commits

Reviewing files that changed from the base of the PR and between b52aa4b and a7e67ce.

⛔ Files ignored due to path filters (5)
  • generated/models/ApiMintingClaimAction.ts is excluded by !**/generated/**
  • generated/models/ApiMintingClaimActionTypesResponse.ts is excluded by !**/generated/**
  • generated/models/ApiMintingClaimActionUpdateRequest.ts is excluded by !**/generated/**
  • generated/models/ApiMintingClaimActionsResponse.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is excluded by !**/generated/**
📒 Files selected for processing (9)
  • __tests__/components/distribution-plan-tool/ReviewDistributionPlanTableSubscriptionFooter.test.tsx
  • __tests__/services/api/memes-minting-claims-api.test.ts
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
  • components/drop-forge/drop-forge-config.ts
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
  • components/waves/memes/submission/details/ArtworkDetails.tsx
  • openapi.yaml
  • services/api/memes-minting-claims-api.ts

Comment thread components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx Outdated
Comment thread openapi.yaml
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (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

📥 Commits

Reviewing files that changed from the base of the PR and between a7e67ce and 8e872ab.

📒 Files selected for processing (5)
  • __tests__/services/api/memes-minting-claims-api.test.ts
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
  • components/drop-forge/drop-forge-config.ts
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/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

Comment thread components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx (1)

665-695: ⚠️ Potential issue | 🟠 Major

Avoid synthesizing completed: false actions when action status payload is unavailable.

At Line 671 and Lines 684-692, when mintingClaimActions is 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8e872ab and 73eb8fb.

📒 Files selected for processing (2)
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx

Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx (1)

847-850: ⚠️ Potential issue | 🟠 Major

Disable 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

📥 Commits

Reviewing files that changed from the base of the PR and between 73eb8fb and 4ed4ef7.

📒 Files selected for processing (4)
  • __tests__/services/api/memes-minting-claims-api.test.ts
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/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

Comment thread components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
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>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

♻️ Duplicate comments (1)
openapi.yaml (1)

9378-9401: ⚠️ Potential issue | 🟠 Major

Response schema constraints still don’t mirror validated inputs.

contract remains unconstrained and claim_id is 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-phase0 null schedule.

Current coverage only checks null schedule on phase0. Add a case where a later phase has schedule: null and 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 on handleMintingClaimActionToggle (line 1147) to invert it with !completed before sending to the API. While this works correctly, it adds unnecessary indirection. Passing e.target.checked directly 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4ed4ef7 and 9a4dddc.

⛔ Files ignored due to path filters (6)
  • generated/models/ApiDistributionAirdropsCsvUploadRequest.ts is excluded by !**/generated/**
  • generated/models/ApiDistributionAirdropsUploadResponse.ts is excluded by !**/generated/**
  • generated/models/ApiDropWinningContext.ts is excluded by !**/generated/**
  • generated/models/ApiIdentityActivity.ts is excluded by !**/generated/**
  • generated/models/DistributionOverview.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is 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.ts
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
  • components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.ts
  • openapi.yaml
  • services/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

Comment thread components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.ts Outdated
Comment thread components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx Outdated
Comment thread openapi.yaml Outdated
Comment thread openapi.yaml
Comment thread openapi.yaml
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>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 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 in UploadDistributionPhotosModal (line 23 uses numbers[0]!.toString()). While both should work correctly given that extractAllNumbers returns 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 including disabled prop in toggle guard for consistency.

The toggle's isActionToggleDisabled guards against claimWritePending and actionPending, but the disabled prop also includes !isInitialized. While !isInitialized typically implies claimWritePending won'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 mock publicEnv.API_ENDPOINT. If the test environment's API endpoint differs, this will fail.

Consider using expect.stringContaining for the path portion or explicitly setting publicEnv.API_ENDPOINT in 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4ed4ef7 and 1bc006d.

⛔ Files ignored due to path filters (6)
  • generated/models/ApiDistributionAirdropsCsvUploadRequest.ts is excluded by !**/generated/**
  • generated/models/ApiDistributionAirdropsUploadResponse.ts is excluded by !**/generated/**
  • generated/models/ApiDropWinningContext.ts is excluded by !**/generated/**
  • generated/models/ApiIdentityActivity.ts is excluded by !**/generated/**
  • generated/models/DistributionOverview.ts is excluded by !**/generated/**
  • generated/models/ObjectSerializer.ts is 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.ts
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooter.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterAutomaticAirdrops.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterConfirmTokenId.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterPhaseAirdrops.tsx
  • components/distribution-plan-tool/review-distribution-plan/table/ReviewDistributionPlanTableSubscriptionFooterUploadPhotos.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.tsx
  • components/drop-forge/launch/DropForgeLaunchClaimPageClient.view.tsx
  • components/drop-forge/launch/drop-forge-launch-claim-page-client.helpers.ts
  • openapi.yaml
  • services/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>
prxt6529 added 10 commits March 17, 2026 10:47
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>
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>
Signed-off-by: prxt6529 <prxt@6529.io>
Signed-off-by: prxt6529 <prxt@6529.io>
@sonarqubecloud
Copy link
Copy Markdown

@prxt6529 prxt6529 merged commit 25a3edc into main Mar 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants