Skip to content

[PLAN] Integrate invite SDK into citizen-claim-widget #85

Description

@L03TJ3

[PLAN] Integrate invite SDK into citizen-claim-widget

Parent: #84

Short description

Plan the full @goodsdks/invite-sdk 1.0.1 integration in @goodwidget/citizen-claim-widget. The embedded Invite Rewards experience must replicate the current GoodWallet invite flow and reward behavior while preserving the widget’s provider-first, viem-based runtime and existing Claim and News behavior.

Confirmed product decisions

  • Invite destination: copy a ready-to-send message that includes the invite code and the exact page URL where the widget is currently loaded (window.location.href). The host supplies no callback, origin, route, or destination configuration. Do not encode the invite code in the URL.
  • Join entry points: support joining an inviter from both the Claim and Invite Rewards tabs. They use the same invite state, validation, and mutation flow; entering a valid code must never produce divergent eligibility or join behavior between tabs.
  • Bounty collection: include the complete GoodWallet-equivalent flow: education/status, eligibility diagnostics, and collection (including batch collection where SDK support applies), not status-only UI.
  • Invite-code algorithm: use GoodWallet’s deterministic algorithm: convert the connected EVM address (without 0x) to bytes, Base58-encode it, then resolve progressively longer prefixes from 10 through 30 characters. The first prefix whose codeToUser result is the zero address is the code. If a prefix resolves to the caller, treat the caller as already registered; if no unused prefix is found, show a retryable generation error. Perform each lookup through InviteSDK.resolveCode; do not reimplement contract resolution or contract preconditions.
  • GoodWallet reference: current GoodWallet copy, reward wording, and visual hierarchy are the source of truth, adapted only for the embedded widget’s existing design-system and accessibility contracts.
  • SDK release/environments: directly consume @goodsdks/invite-sdk 1.0.1. It supports Celo and XDC; production uses production InvitesV2 addresses, and staging normalizes to the SDK’s development contract environment.

Repositories, packages, and reference files

GoodWidget

  • packages/citizen-claim-widget/src/CitizenClaimWidget.tsx — existing Claim / Invite Rewards / News shell; replace only the Invite Rewards placeholder and add the approved Claim-tab entry point without altering claim behavior.
  • packages/citizen-claim-widget/src/adapter.ts — reuse the EIP-1193-to-viem client factory, environment normalization, and SDK adapter pattern for invite reads/writes.
  • packages/citizen-claim-widget/src/widgetRuntimeContract.ts and integration.ts — extend runtime state/actions/events without changing existing public claim contracts.
  • packages/citizen-claim-widget/package.json — add the direct @goodsdks/invite-sdk@1.0.1 dependency.
  • examples/storybook/src/stories/citizen-claim-widget/ and tests/widgets/citizen-claim-widget/ — widget stories, fixtures, Playwright smoke coverage, and screenshot evidence.
  • docs/demo-environment.md — Storybook and Playwright verification conventions.

GoodSDKs

  • packages/invite-sdk/src/sdks/viem-invite-sdk.ts — typed InviteSDK reads, resolveCode, join prechecks/simulation, writes, eligibility diagnostics, and bounty collection.
  • packages/invite-sdk/src/types.ts — invite user/level/stat types, eligibility results, collection results, and typed errors.
  • packages/invite-sdk/src/constants.ts — Celo/XDC support and production/development address resolution; staging maps to development.
  • packages/invite-sdk/package.json — published package/version and viem peer dependency.

GoodWallet UX/UI source of truth

  • src/sections/GoodDollar/components/Invite/InviteView.tsx — hierarchy: campaign reward headline, invitee reward, “How it works”, share/join, code entry, total rewards, and invitee status.
  • src/sections/GoodDollar/components/Invite/components/ShareLinkBox.tsx — join/register before a code is available, pending/success/error feedback, and native share/copy behavior.
  • src/sections/GoodDollar/components/Invite/components/InvCodeBox.tsx — debounced code validation; hide entry after joining an inviter or receiving the invitee bounty.
  • src/gooddollar/stores/inviteStore.ts — Base58 prefix generation rule, codeToUser lookup, invite data aggregation, and collection eligibility inputs.
  • src/sections/GoodDollar/components/Invite/components/TotalEarnedBox.tsx and InviteesListBox.tsx — cumulative-reward and pending-versus-approved invitee presentation.

Required states, flows, and behaviors

Shared invite flow

  • Keep Claim and News behavior unchanged. Both approved entry points consume one shared invite runtime state and actions.
  • Handle disconnected, unsupported network, initial loading, refresh, retryable read error, invalid code, join pending, join success, and retryable mutation error states.
  • Limit transactions to SDK-supported Celo/XDC. On unsupported networks, show a clear non-transactional state and do not attempt writes.
  • Load the caller’s invite user, bounty level, invitees, pending invitees/count, collection eligibility diagnostics, and minimum-claims/minimum-days rules.
  • Validate a submitted code through InviteSDK.resolveCode before join. Reject malformed/unknown codes, the caller’s own code, and codes when the caller has already joined. A code becomes usable only after its owner’s join transaction succeeds.
  • Submit all joins through InviteSDK prechecks/simulation and its join transaction. Prevent duplicate submissions while pending. Present NOT_ACTIVE, INVITE_CODE_IN_USE, SELF_INVITE, USER_ALREADY_JOINED, and unknown errors as concise actionable messages.
  • Refresh all invite data after successful joins and collections; preserve an explicit retry action after failed reads or mutations.

Invite Rewards tab

  • Mirror GoodWallet’s visual hierarchy and current copy: reward headline, invitee reward, accessible “How it works” disclosure (share, signup/join, claim/day eligibility period, reward receipt), share/create card, code-entry card, total earned, and invitee/pending status.
  • For verified callers without a personal code, offer join/register to create one using the confirmed deterministic algorithm and SDK-backed lookups/prechecks.
  • Once a code exists, copy a message in this form: Claim GoodDollar with me. Open this page and use my invite code: <code>\n<current-page-url>. Use Web Share when available and clipboard fallback with success/error feedback.
  • Show the code-entry control only while the recipient remains eligible to join an inviter. The same control/action is also available from the Claim tab.
  • Show pending invitees separately from reward-eligible/paid invitees. Include full collection controls, using SDK eligibility diagnostics before collection and batch results where supported. Never imply rewards are collectible before whitelist, minimum-days, and minimum-claims conditions are satisfied.

Integration constraints

  • Align the SDK environment with the widget’s production, staging, and development selection; rely on InviteSDK’s documented staging-to-development resolution.
  • Do not copy InvitesV2 ABI, address resolution, contract prechecks, simulation, error mapping, or join/collection logic into GoodWidget.
  • Keep invite-specific state orchestration and components in packages/citizen-claim-widget. Reuse @goodwidget/ui primitives; move nothing to packages/ui unless it is demonstrably reusable across widgets.
  • Preserve existing public claim props/events and named theme targets. Treat any required invite-specific event or theme target as documented public API.

Execution plan

  1. Verify the current citizen-claim runtime boundaries, Claim-tab integration point, and existing SDK/client versions; add @goodsdks/invite-sdk@1.0.0 as a direct widget dependency.
  2. Extend the adapter/runtime contract with a shared invite state machine, typed SDK error mapping, refresh semantics, and supported-chain initialization using the existing viem clients.
  3. Implement the deterministic GoodWallet invite-code generator using only InviteSDK code resolution, then wire InviteSDK validation, join prechecks/simulation, join writes, collection eligibility, and collection writes.
  4. Build widget-local components matching the GoodWallet hierarchy: reward/education, create/share, shared join-with-code, earned rewards, invitee/pending list, and collection feedback. Surface the shared join control from both Claim and Invite Rewards.
  5. Implement current-page message generation, Web Share support, and clipboard fallback without host URL configuration.
  6. Add explicit loading, empty, verification-required, unsupported-chain, invalid-code, join-pending, join-success, collection-pending/success, SDK-error, and RPC-error views.
  7. Add Storybook examples for injected and custodial fixtures, ready-to-share, both join entry points, eligibility/pending states, collection, empty state, and errors.
  8. Add Playwright smoke coverage for main, empty, error, and collection flows, with page.screenshot() calls and curated screenshot evidence under the widget test convention.
  9. Update widget-facing documentation for supported networks, SDK version, no-host-URL-config behavior, shared join entry points, collection lifecycle, public API, and limitations.
  10. Run repository/package lint, build, Storybook interaction, and Playwright checks; verify Claim/News regression coverage and document visual evidence in the PR.

Acceptance criteria

  • @goodwidget/citizen-claim-widget directly consumes @goodsdks/invite-sdk@1.0.1 and does not duplicate InvitesV2 protocol logic.
  • Invite URL sharing copies the current loaded page URL alongside the code; no integrator URL/callback configuration exists.
  • Users can join an inviter from both Claim and Invite Rewards through the same validated, pending-safe flow.
  • A personal invite code follows GoodWallet’s Base58, shortest-unused-prefix algorithm and is usable only after a successful join transaction.
  • Invite Rewards replicates GoodWallet’s current copy, reward hierarchy, education, reward status, pending/approved invitee presentation, and full bounty-collection functionality.
  • Code validation resolves on-chain through InviteSDK and rejects unknown, self, and already-joined cases before joining.
  • All writes use InviteSDK prechecks/simulation and provide loading, invalid-code, pending, success, typed-error, and retry states.
  • Unsupported-chain, disconnected, loading, empty, verification-required, validation, RPC-error, and transaction-error states are intentional and testable.
  • No wagmi or React Query dependency is introduced; new invite UI remains widget-local unless a reusable primitive is approved.
  • Storybook covers injected/custodial fixtures and all planned flow states; Playwright covers main, empty, and error flows with page.screenshot() evidence.
  • Documentation records Celo/XDC support, production/staging behavior, version, no-host-URL-config behavior, host events/theme targets, and limitations.
  • Existing lint/build/test commands pass and Claim/News behavior continues to pass regression coverage.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Fields

No fields configured for Task.

Projects

Status
Prepare AI Task

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions