Skip to content

fix(claim): show loading spinner while claim data loads on network switch (#614) - #646

Closed
ocakciomursel-pixel wants to merge 3 commits into
GoodDollar:masterfrom
ocakciomursel-pixel:fix/claim-button-loading-state-614
Closed

ocakciomursel-pixel wants to merge 3 commits into
GoodDollar:masterfrom
ocakciomursel-pixel:fix/claim-button-loading-state-614

Conversation

@ocakciomursel-pixel

@ocakciomursel-pixel ocakciomursel-pixel commented Oct 17, 2026 •

Copy link
Copy Markdown

Summary

Fixes #614.

Problem

When switching to XDC (chainId === 50, which renders OldClaim) or switching networks while connected:

  1. useClaim first resolves whitelistedRoot + periodStart/currentDay, and only after whitelistedRoot resolves does useEntitlementForRoot fetch claimAmount (checkEntitlement).
  2. During that two-step loading window, claimAmount and claimed are undefined, causing ClaimButton to render a blue button saying "CLAIM NOW" (without the claim amount) and with disabled={undefined}, where pressing it does nothing.
  3. Additionally, OldClaim did not pass refresh={refreshRate} to ClaimButton, leaving ClaimButton's internal useClaim hook at its default "never" refresh setting instead of "everyBlock" on chain switch.

Solution

  • Compute isClaimDataLoading when a wallet is connected on a claim-enabled chain and either the initial UBI/Identity multicall has not resolved yet or the user is whitelisted while claimAmount / claimed are still resolving.
  • Render a <Spinner variant="page-loader" size="lg" /> while isClaimDataLoading is true and guard handleClaim against premature invocation.
  • Pass refresh={refreshRate} to <ClaimButton /> so its internal useClaim hook stays synchronized with OldClaim's polling rate.

Fixes #614

Summary by Sourcery

Prevent incomplete claim data from rendering an actionable claim button during network transitions.

Bug Fixes:

  • Show a loading spinner while claim data is being resolved after connecting or switching networks, preventing premature claim interactions.
  • Provide a retry state when claim data cannot be loaded within the timeout period.

Enhancements:

  • Keep claim polling synchronized during network changes and guard claim execution until required data is available.

…itch (GoodDollar#614)

- Detect in-flight UBI/Identity multicall and entitlement resolution after switching networks (e.g., to XDC)
- Render a page-loader Spinner instead of an unresponsive blue "CLAIM NOW" button while claim data is loading
- Forward refresh={refreshRate} to ClaimButton so it polls everyBlock on network switch

Fixes GoodDollar#614

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/pages/gd/Claim/OldClaim.tsx" line_range="158-162" />
<code_context>
     )

+    const isClaimDataLoading = Boolean(
+        address &&
+            (activeChainFeatures['claimEnabled'] || !isProd || isMinipay) &&
+            (!nextClaimTime ||
+                nextClaimTime.getTime() <= INITIAL_PERIOD_EPOCH_MS ||
+                (isWhitelisted && (claimAmount === undefined || claimed === undefined)))
+    )
+
</code_context>
<issue_to_address>
**Previous chain data remains visible**

When the wallet switches chains while `useClaim` still exposes the previous chain’s resolved data, `isClaimDataLoading` and the outer `claimed` branch consume that data before the new entitlement resolves, so the old claim button remains actionable or the old claimed view appears. The user sees the wrong chain’s claim state.

Bind claim data to the active chain and keep both the claim button and claimed view behind loading until the new chain’s data is ready.

Also at `src/pages/gd/Claim/OldClaim.tsx:437-440`.
</issue_to_address>

### Comment 2
<location path="src/pages/gd/Claim/OldClaim.tsx" line_range="160-162" />
<code_context>
+    const isClaimDataLoading = Boolean(
+        address &&
+            (activeChainFeatures['claimEnabled'] || !isProd || isMinipay) &&
+            (!nextClaimTime ||
+                nextClaimTime.getTime() <= INITIAL_PERIOD_EPOCH_MS ||
+                (isWhitelisted && (claimAmount === undefined || claimed === undefined)))
+    )
+
</code_context>
<issue_to_address>
**Claim page stays loading**

When the claim-data request fails or never supplies `nextClaimTime`, `isClaimDataLoading` remains true, so the spinner replaces `ClaimButton` indefinitely and the user has no in-page error or retry.

Handle a missing `nextClaimTime` after a failed or stalled request with an error state and a retry path instead of keeping the page loading.

Also at `src/pages/gd/Claim/OldClaim.tsx:437-441`.
</issue_to_address>

### Comment 3
<location path="src/pages/gd/Claim/OldClaim.tsx" line_range="452" />
<code_context>
-                                        handleConnect={handleConnect}
-                                        chainId={+(chainId ?? 42220)}
-                                        onEvent={handleEvents}
-                                    />
+                                    {isClaimDataLoading ? (
+                                        <Center w="full" py="12">
</code_context>
<issue_to_address>
**Claim reads poll twice per block**

When a connected user has an unclaimed amount and the page is open, `refreshRate` is set to `everyBlock` whenever an unclaimed `claimAmount` is available, so forwarding it makes `ClaimButton`'s internal `useClaim` poll alongside the page's existing `useClaim`. The duplicate polling increases RPC traffic and can hit provider limits.

Avoid polling the same claim data from both components, or share the page's claim data with `ClaimButton` instead of forwarding an every-block refresh rate.
</issue_to_address>

Sourcery assessment

Approval pending. 3 findings to address first.

Blocking findings: src/pages/gd/Claim/OldClaim.tsx:162, src/pages/gd/Claim/OldClaim.tsx:162, src/pages/gd/Claim/OldClaim.tsx:452


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread src/pages/gd/Claim/OldClaim.tsx
Comment thread src/pages/gd/Claim/OldClaim.tsx Outdated
Comment thread src/pages/gd/Claim/OldClaim.tsx Outdated
ocakciomursel-pixel added 2 commits October 17, 2026 22:15
…n stall (GoodDollar#614)

- Track dataChainId to prevent previous chain entitlement from rendering on chain switch
- Keep both ClaimBalance and ClaimButton behind loading state until active chain resolves
- Add timeout and Retry button for stalled or failed claim data requests
- Remove refresh prop on ClaimButton to avoid duplicate every-block polling

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sourcery assessment

Approved.

@L03TJ3 L03TJ3 closed this Oct 19, 2026

This branch is waiting to be deployed

1 waiting deployment
external — e88ca5a1 Waiting Oct 17, 2026 by ocakciomursel-pixel via authorize #1074
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.

Bug: claim button appears clickable while loading claim data

2 participants