Skip to content

feat: add claimable revenue section and claim UI to contributor dashboard (closes #589) - #862

Open
Cyber-Mitch wants to merge 2 commits into
Iris-IV:mainfrom
Cyber-Mitch:feature/dashboard-claim-revenue-ui
Open

feat: add claimable revenue section and claim UI to contributor dashboard (closes #589)#862
Cyber-Mitch wants to merge 2 commits into
Iris-IV:mainfrom
Cyber-Mitch:feature/dashboard-claim-revenue-ui

Conversation

@Cyber-Mitch

Copy link
Copy Markdown

closes #589

Description

Adds a "Claimable Revenue" section to the contributor dashboard, showing all EducationalStartup campaigns with unclaimed revenue and a one-click Claim button per campaign. Closes #589.

Changes

  • src/components/ClaimableRevenueSection.tsx (new, ~155 lines) — dashboard section that reads from the existing useContributions hook, filters to category === EducationalStartup && canClaimRevenue && claimable > 0, and renders a card/row per campaign with the campaign title, formatted claimable amount (XLM), a per-row Claim button, and a header total.
  • src/app/[locale]/dashboard/DashboardClient.tsx (modified, +3 lines) — one import + render call to mount the new section at the top of the dashboard.
  • src/__tests__/components/ClaimableRevenueSection.test.tsx (new, 8 tests) — covers rendering, header total, filtering (excludes non-EducationalStartup and zero-claimable rows), success path, empty state, loading state, and sibling-button disabling during an in-flight claim.

Recon Notes

  • Claim binding: the issue references claim_creator_revenue, but the actual wired binding in this frontend is claimRevenue(campaignId, contributor, options?) (src/lib/contractClient.ts:937), which invokes the on-chain method claim_revenue. It builds and signs a Soroban transaction through the active wallet signer (Freighter/social login), returns a txHash, throws parsed contract errors, and accepts an onStatus lifecycle callback. No binding changes were needed — naming discrepancy noted for visibility only, not a blocker.
  • Claimable read: no single view returns "claimable" directly. The app already computes it canonically in useContributions, combining three real contract views — get_contribution, get_revenue_pool, get_revenue_claimed — via claimable = (contribution × pool) ÷ .... Reused this existing hook rather than fabricating a new data source.
  • Decimal/unit handling: stroops (1 XLM = 10⁷ stroops), displayed via the existing audited formatAmount(stroops, locale, { maximumFractionDigits: 4 }) utility — no new formatter written.
  • Conventions followed: shared loading/error/empty-state patterns, Card component, Tailwind, useToast (showSuccess/showError), React Query for data fetching, useWallet() for signer state.

Claim Flow States

  • Pending: clicking Claim shows a spinner with phase-aware labels (Signing…Confirming…); all claim buttons disable during any in-flight claim (disabled={pendingCampaignId !== null}).
  • Success: showSuccess() toast fires, then refetch() — the claimed row's amount recomputes to 0 and drops out of the list without a page reload.
  • Failure: the actual parsed contract error is surfaced via showError() — no silent failures.
  • Empty: dashed-border empty state, consistent with the existing ContributionsSection pattern. Hook loading and error states are also handled.

Blockers

  • None for this feature — the claimable-revenue read and the claim binding both already existed and were simply wired up.
  • Pre-existing, unrelated issue flagged (not touched): src/components/WalletContext.tsx has a type gap (WalletContextType missing walletKind/socialProfile/isSocialLoginAvailable/connectWithSocial) that fails tsc/the Next build step. This was present in the baseline before this change and is out of scope — fixing it here would be scope creep. My new component compiles cleanly on its own.

Test Results

New suite: 8/8 passing.

Full suite: 10 failed / 51 passed (suites), consistent with baseline's 10 pre-existing failing suites — no regressions introduced. +8 new passing tests from this change.

  • Lint: 0 errors on new files (48 pre-existing, unrelated).
  • Typecheck: clean except the pre-existing WalletContext.tsx:373 error noted above.
  • Build: compiles successfully; fails only at the pre-existing WalletContext.tsx:373 typecheck step, same as baseline.

Checklist

  • Dashboard shows a "Claimable Revenue" section (ClaimableRevenueSection.tsx:98)
  • Lists all campaigns with unclaimed revenue, filtered correctly (ClaimableRevenueSection.tsx)
  • Correctly-formatted claimable amount (stroops → XLM)
  • One-click Claim button calls claimRevenue(campaignId, walletAddress, { onStatus }) with correct args
  • Pending/loading, success, and error states all handled and visible (:56-70 handler, :75-79 labels, :92-93 loading)
  • Empty state handled (:99-101)
  • No contract binding/logic changes — git status shows only the new component, its test, and the 3-line dashboard integration

@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@Cyber-Mitch Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@sshdopey

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@sshdopey

Copy link
Copy Markdown
Contributor

Auto-review failed (API error). Leaving PR for human review.

@davidmaronio davidmaronio 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.

this is a strong feature PR. the component reuses the canonical claimable computation from useContributions instead of inventing a new data source, the tx lifecycle phases drive the button label, sibling claim buttons are disabled while one claim is in flight, and the test suite covers rendering, filtering, success, failure, empty, loading, error, and the in-flight disable. typecheck, build, and unit tests are all green.

on the overlap question: #691 is a claim-all button for refunds in MyContributionsSection, different feature and different files, so these do not conflict and both can land.

asks before merge:

  1. branch name: the "Validate branch name" check fails, and that one is a real failure, not the stale-base issue. this likely means opening a fresh PR from a conventionally named branch or renaming the branch per CONTRIBUTING.md.
  2. src/components/ClaimableRevenueSection.tsx:299 onward - all user-facing strings ("Claimable Revenue", "Revenue claimed successfully.", the empty state, "Signing...", etc.) are hardcoded english. the rest of the dashboard goes through next-intl (you already call useLocale for number formatting), so please add these to messages/en.json and es.json and use useTranslations.
  3. src/components/ClaimableRevenueSection.tsx:303 - showError(parseContractError(err)) can surface a raw "ContractErrors.xyz" namespace key; #858 is fixing exactly this pattern elsewhere. once your strings go through next-intl, run the parsed error through the same localization helper.
  4. minor: aria-label={Claim revenue for ${title}} will also need i18n once item 2 is done.

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.

[Feature] Add revenue claiming UI for EducationalStartup contributors on dashboard

3 participants