From 5426ee3784096601b2da4d2217f1c5638b0004ee Mon Sep 17 00:00:00 2001 From: LewisB Date: Mon, 4 May 2026 18:24:11 +0700 Subject: [PATCH 01/41] remove bounty template and references to it, remove alignment with pull-requests --- .github/ISSUE_TEMPLATE/agent-ready-bounty.yml | 351 ------------------ .github/copilot-instructions.md | 6 - ARCHITECTURE.md | 48 ++- 3 files changed, 23 insertions(+), 382 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/agent-ready-bounty.yml diff --git a/.github/ISSUE_TEMPLATE/agent-ready-bounty.yml b/.github/ISSUE_TEMPLATE/agent-ready-bounty.yml deleted file mode 100644 index 2b2ebb4..0000000 --- a/.github/ISSUE_TEMPLATE/agent-ready-bounty.yml +++ /dev/null @@ -1,351 +0,0 @@ -name: Agent-ready bounty -description: Create a GoodBounty issue that is readable by humans, executable by Copilot, and reviewable by contributors. -title: '[GoodBounty]: ' -labels: ['enhancement'] -body: - - type: markdown - attributes: - value: | - Use this template for GoodBounties that may be assigned to Copilot or another coding agent before human contributor review. - - The goal is not to write a long prompt. The goal is to create a clear execution contract: - - humans can understand the bounty quickly - - Copilot has enough context to produce a scoped PR - - reviewers can verify the PR against explicit criteria - - - type: input - id: bounty-summary - attributes: - label: Human summary - description: One sentence describing the outcome. Keep this readable for contributors browsing the board. - placeholder: 'Migrate the GoodWalletV2 claim flow into the Citizen Claim Widget using GoodSDKs.' - validations: - required: true - - - type: textarea - id: why-this-matters - attributes: - label: Why this matters - description: Explain the product or architecture reason in 2–4 sentences. - placeholder: | - This moves the widget closer to a real SDK-backed claim flow and gives us a reusable reference for future GoodWidget migrations. - validations: - required: true - - - type: dropdown - id: bounty-tier - attributes: - label: Bounty tier - description: Pick the expected bounty tier. Adjust before assignment if scope changes. - options: - - Basic - - Common - - Rare - - Epic - - Mythic - - Legendary - validations: - required: true - - - type: dropdown - id: bounty-type - attributes: - label: Bounty type - description: Choose the closest category. - options: - - Bug fix - - UI implementation - - Widget feature - - SDK integration - - Architecture cleanup - - Primitive migration - - Documentation - - QA / review - - Research / specification - validations: - required: true - - - type: input - id: target-package - attributes: - label: Target package or area - description: Main package, app, or folder this bounty should touch. - placeholder: 'packages/citizen-claim-widget' - validations: - required: true - - - type: input - id: base-branch - attributes: - label: Required base branch - description: The branch Copilot or the contributor must start from. - placeholder: 'main' - value: 'main' - validations: - required: true - - - type: textarea - id: required-references - attributes: - label: Required references - description: List all files, PRs, branches, docs, or external repositories that must be inspected before implementation. - value: | - The agent and contributor must inspect these before implementation: - - - `ARCHITECTURE.md` - - `AGENTS.md` - - `docs/demo-environment.md` - - Relevant source files / PRs / branches: - - - - If any required reference is unavailable, stop and comment exactly what is missing. - placeholder: | - - GoodWidget PR #... - - GoodSDKs PR #... - - GoodWalletV2/src/... - validations: - required: true - - - type: textarea - id: source-to-target-mapping - attributes: - label: Source-to-target mapping - description: Required for migrations or feature parity work. This prevents shallow “review related files” behavior. - value: | - Before coding, produce or complete this mapping. - - | Source behavior / UI section | Target widget section | Required state / prop / API | Verification | - |---|---|---|---| - | | | | | - | | | | | - | | | | | - - If this bounty is not a migration/parity task, explain why this mapping is not needed. - validations: - required: true - - - type: textarea - id: scope - attributes: - label: Scope - description: Be explicit about what must change and what may change. - value: | - Must change: - - - - May change: - - - - Must not change: - - - validations: - required: true - - - type: textarea - id: non-goals - attributes: - label: Non-goals - description: List anything tempting but out of scope. - value: | - Do not include: - - unrelated refactors - - unrelated design-system changes - - unrelated dependency upgrades - - changes outside the target package unless explicitly listed in scope - validations: - required: true - - - type: checkboxes - id: architecture-constraints - attributes: - label: Architecture constraints - description: Check all constraints that apply. These become review criteria. - options: - - label: Keep SDK/protocol logic out of `packages/ui`. - required: false - - label: Keep widget-specific flow logic inside the widget package. - required: false - - label: Preserve the provider-first runtime path through `GoodWidgetProvider`. - required: false - - label: Preserve the current theming override precedence. - required: false - - label: Do not introduce new public theme targets unless explicitly listed. - required: false - - label: Do not bypass the EIP-1193/provider wrapper model. - required: false - - label: Do not modify demo packages except for explicit Storybook or verification deliverables. - required: false - - label: Do not touch unrelated primitives, packages, or dependencies. - required: false - - - type: textarea - id: acceptance-criteria - attributes: - label: Acceptance criteria - description: These are the main pass/fail checks for the bounty. - value: | - - [ ] - - [ ] - - [ ] - - [ ] - validations: - required: true - - - type: textarea - id: states-and-flows - attributes: - label: Required states, flows, or behaviors - description: Use this especially for UI, wallet, claim, transaction, or async flows. - value: | - | State / flow | Trigger | Expected behavior | Verification | - |---|---|---|---| - | loading | | | | - | | | | | - - If no state machine or flow behavior is involved, write: "No state/flow matrix needed." - validations: - required: true - - - type: textarea - id: sdk-and-version-checks - attributes: - label: SDK, dependency, and cross-repo checks - description: Make version assumptions explicit. This avoids PR #11-style mismatch between unreleased SDK changes and published packages. - value: | - Required SDK/package assumptions: - - - - Cross-repo dependencies: - - - - Required check: - - [ ] Confirm whether referenced SDK/API changes are already released, branch-only, local-only, or pending release. - - [ ] If there is a version/capability gap, report it before implementing a workaround. - validations: - required: false - - - type: textarea - id: storybook-requirements - attributes: - label: Storybook requirements - description: Required for UI/widget work. Use Storybook as the canonical visual/review environment. - value: | - - [ ] Add or update a Storybook story. - - [ ] Include deterministic mock fixtures if wallet/provider state is needed. - - [ ] Add visible `data-testid` values for important states. - - [ ] Cover at least these stories/states: - - - - [ ] Add or update play-function tests if interaction behavior is part of the bounty. - validations: - required: false - - - type: textarea - id: visual-requirements - attributes: - label: Visual and UX requirements - description: Do not say “match the demo” without listing the visible sections or states that must match. - value: | - Required visible sections / UI details: - - - - Required responsive checks: - - Desktop: - - Mobile / narrow viewport: - - Screenshots or recordings required: - - - validations: - required: false - - - type: textarea - id: verification-commands - attributes: - label: Verification commands - description: Commands Copilot/contributor should run and report in the PR body. - value: | - Run and report: - - ```sh - pnpm build - pnpm test:storybook - pnpm test:demo - ``` - - If any command cannot run, explain why and what was run instead. - validations: - required: true - - - type: textarea - id: pr-requirements - attributes: - label: Pull request requirements - description: The PR must mirror the issue and provide review evidence. - value: | - The PR description must include: - - - Summary of changes - - Source-to-target mapping, if applicable - - Acceptance criteria checklist - - Commands run - - Storybook links, screenshots, or recordings for UI changes - - Known risks / follow-ups - - Any intentional deviations from this issue - validations: - required: true - - - type: checkboxes - id: human-reviewer-checklist - attributes: - label: Human reviewer checklist - description: Reviewers should use this before approving or requesting maintainer sign-off. - options: - - label: I reviewed the issue before reviewing the diff. - required: false - - label: I checked whether the PR solves the stated goal, not just a related problem. - required: false - - label: I checked scope boundaries and unrelated file changes. - required: false - - label: I checked architecture constraints. - required: false - - label: I reviewed Storybook or visual evidence where relevant. - required: false - - label: I checked verification command output or reproduced the checks. - required: false - - label: I left concrete review comments or fixed blockers directly. - required: false - - - type: textarea - id: risks-and-followups - attributes: - label: Known risks and follow-ups - description: Capture uncertainty before implementation starts. - placeholder: | - - SDK release dependency may not be published yet. - - Storybook fixture may not cover real wallet behavior. - - Follow-up bounty may be needed for ... - validations: - required: false - - - type: checkboxes - id: spec-readiness-check - attributes: - label: Spec readiness check - description: Complete this before assigning the bounty to Copilot or a contributor. - options: - - label: Required references are listed and accessible. - required: true - - label: Scope and non-goals are clear. - required: true - - label: Source-to-target mapping is complete, or explicitly marked not applicable. - required: true - - label: SDK/version assumptions are checked, or explicitly marked not applicable. - required: true - - label: Acceptance criteria are testable. - required: true - - label: Storybook/Playwright expectations are clear, or explicitly marked not applicable. - required: true - - label: Verification commands are listed. - required: true - - label: This issue is ready for Copilot execution. - required: true diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6add65e..d7f20a9 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -6,9 +6,3 @@ When asked to create or refine a GoodBounty issue: - Use `ARCHITECTURE.md` for package/runtime boundaries. - Use `docs/demo-environment.md` for Storybook and Playwright verification expectations. - Read `docs/architecture/theming-contract.md` only if the spec requires changes to Tamagui config, tokens, themes, presets, primitives, component names, public override targets, or theming behavior. - -- Use `.github/ISSUE_TEMPLATE/agent-ready-bounty.yml` as the required structure for bounty specification. - - Produce a complete issue body. - - Identify missing references, assumptions, SDK/version gaps, and verification requirements. - - Stop after the bounty specification is drafted. - - Do not implement, branch, assign yourself, or open a PR unless explicitly asked in a separate follow-up after human approval. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c37b06d..368a0e0 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,8 +1,6 @@ # GoodWidget Architecture This document is the authoritative reference for the current GoodWidget codebase. -It is aligned to the `copilot/sub-pr-6` branch and the current Tamagui architecture used in -`packages/ui`, `packages/core`, `packages/embed`, and `packages/claim-widget`. For detailed Tamagui/theming rules, see [`docs/architecture/theming-contract.md`](docs/architecture/theming-contract.md). @@ -179,15 +177,15 @@ And finally there are local component-instance props: ### Key files -| File | Responsibility | -|------|----------------| -| `configTypes.ts` | Public config, token, theme, preset, typography, animation types | -| `theme.ts` | Plain token seeds + `createGoodWidgetTokens()` + `createThemeValues()` | -| `presets.ts` | GoodWalletV2 preset tokens and partial theme overrides | -| `config.ts` | Config resolution, token override merge, theme derivation, `createGoodWidgetConfig()` | -| `createComponent.ts` | Named styled-component wrapper + manifest registration | -| `manifest.ts` | Runtime manifest for named override targets | -| `index.ts` | Public exports | +| File | Responsibility | +| -------------------- | ------------------------------------------------------------------------------------- | +| `configTypes.ts` | Public config, token, theme, preset, typography, animation types | +| `theme.ts` | Plain token seeds + `createGoodWidgetTokens()` + `createThemeValues()` | +| `presets.ts` | GoodWalletV2 preset tokens and partial theme overrides | +| `config.ts` | Config resolution, token override merge, theme derivation, `createGoodWidgetConfig()` | +| `createComponent.ts` | Named styled-component wrapper + manifest registration | +| `manifest.ts` | Runtime manifest for named override targets | +| `index.ts` | Public exports | ### Theme model summary @@ -230,14 +228,14 @@ cover how to reduce that transitional surface. ### Key files -| File | Responsibility | -|------|----------------| -| `eip1193.ts` | EIP-1193 types | -| `detect.ts` | Host/provider detection | -| `types.ts` | Provider props and host/wallet state types | -| `provider.tsx` | `GoodWidgetProvider` | -| `hooks.ts` | `useWallet()`, `useHost()`, `useGoodWidget()` | -| `wagmi.ts` | wagmi integration surface | +| File | Responsibility | +| -------------- | --------------------------------------------- | +| `eip1193.ts` | EIP-1193 types | +| `detect.ts` | Host/provider detection | +| `types.ts` | Provider props and host/wallet state types | +| `provider.tsx` | `GoodWidgetProvider` | +| `hooks.ts` | `useWallet()`, `useHost()`, `useGoodWidget()` | +| `wagmi.ts` | wagmi integration surface | ### Provider flow @@ -258,12 +256,12 @@ boundary. ### Key files -| File | Responsibility | -|------|----------------| -| `createMiniAppElement.tsx` | Web Component factory | -| `cssPropertyBridge.ts` | Reads `--gw-*` overrides from the host | -| `shadowStyles.ts` | Shadow DOM reset and runtime style syncing | -| `bridge.ts` | attribute/prop/event bridging | +| File | Responsibility | +| -------------------------- | ------------------------------------------ | +| `createMiniAppElement.tsx` | Web Component factory | +| `cssPropertyBridge.ts` | Reads `--gw-*` overrides from the host | +| `shadowStyles.ts` | Shadow DOM reset and runtime style syncing | +| `bridge.ts` | attribute/prop/event bridging | ### Web Component behavior From 859ff06b14c573afc60ce282c69a69777f6d1036 Mon Sep 17 00:00:00 2001 From: LewisB Date: Tue, 5 May 2026 13:55:04 +0700 Subject: [PATCH 02/41] fix: copilot setup steps name --- .github/workflows/copilot-setup-steps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index cebfd38..218e228 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -19,7 +19,7 @@ on: workflow_call: {} jobs: - setup: + copilot-setup-steps: runs-on: ubuntu-latest steps: # 1. Enable corepack so the declared pnpm version (packageManager field) is used From 8a72719c4c1598c57e086c22fc0fa45371eb2687 Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 19:21:43 +0700 Subject: [PATCH 03/41] add goodwidget specific copilot instructions + simplified bounty-spec template --- .github/bounty-spec-template.md | 51 +++++++++++++++++++++++++++++++++ .github/copilot-instructions.md | 28 ++++++++++++++++-- 2 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 .github/bounty-spec-template.md diff --git a/.github/bounty-spec-template.md b/.github/bounty-spec-template.md new file mode 100644 index 0000000..7ce6aa0 --- /dev/null +++ b/.github/bounty-spec-template.md @@ -0,0 +1,51 @@ +# Bounty Spec Template + +Use this as the minimal starting point for a GoodBounty issue spec. + +## Context and goals + +- Why is this issue being created? +- What problem does it solve? +- How does it fit the project goals? + +## Reference: key files and features + +- Relevant files: +- Relevant features: +- Cross-repository dependencies: +- Package or dependency assumptions: + +## New components and design references + +- UX flows or screenshots: +- Core/UI components to reuse: +- New components to create: + +## Required flows + +- Required states: +- Expected behavior in each state: +- Error and empty states: + +## Execution plan + +1. Implementation: +2. Testing and validation: + +### Acceptance criteria + +Usage/demo included + +- [ ] Criterion 1 +- [ ] Criterion 2 +- [ ] Criterion 3 +- [ ] includes storybook examples and smoke tests using playwright +- [ ] includes screenshots from the different UI states and flows +- + +### Human reviewer checklist + +- [ ] Code matches the issue scope +- [ ] Required flows are implemented +- [ ] Validation steps were run +- [ ] Documentation was updated if needed diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index d7f20a9..9df7a2b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,8 +1,32 @@ -## Bounty authoring rule +## Working with GoodWidget (General) -When asked to create or refine a GoodBounty issue: +Repository overview: - Follow `AGENTS.md` for bounty-spec behavior and document routing. - Use `ARCHITECTURE.md` for package/runtime boundaries. - Use `docs/demo-environment.md` for Storybook and Playwright verification expectations. - Read `docs/architecture/theming-contract.md` only if the spec requires changes to Tamagui config, tokens, themes, presets, primitives, component names, public override targets, or theming behavior. + +## How to work in the repository + +- New widgets should always have their own package under `packages/` with a clear name and description. +- Follow the existing package structure and conventions for new widget packages. +- For new widgets, new components and UI changes, always include Storybook examples and Playwright smoke tests. organized by widget specific folders. +- For any new component or significant change, include clear comments and documentation. +- Always verify when to modularize large components/hooks and avoid single line helpers. +- Any new widget related components should be added to the widget's own package and not to `packages/ui` unless they are general purpose and reusable across multiple widgets. + +## How to work with storybook and playwright + +- storybook examples should demonstrate the expected behavior and states of the widget. + it should include both custodial and non-custodial flows and use the appropriate fixtures for each case. + fixtures to use: `examples/storybook/fixtures/custodialEip1193.ts` and `examples/storybook/fixtures/injectedEip1193.ts`. +- stories should be organized per widget. For base components from packages/ui it should be part of the 'theme' folder, demonstrating the usage of the component with the theming system. +- Playwright smoke tests should cover the main flows and states of the widget, including error and empty states. They should be organized in the same way as the storybook examples, with separate test files for each widget and for the base components in `packages/ui`. +- Playwright smoke tests should always include page.screenshot() calls to capture the different UI states and flows, and these screenshots should be included in the pull-request description and should always sync with the latest screenshots taken. +- Playwright screenshots should be organized as part of the smoke-test per widget directory, and should be named according to the flow and state they represent for easy reference. + +## Define a GoodBounty issue spec + +When asked to create or refine a GoodBounty issue make sure to follow the structure from the bounty spec template: `.github/bounty-spec-template.md` and include all the sections and details described there. Always ask for clarification if any of the sections cannot be filled with the available information or if you are not sure about any of the details. +Be as concise as possible while still providing all the necessary information for the implementation and validation of the issue. The more clear and easy to understand the spec is, the easier it will be for the implementer to understand the requirements and for the reviewer to validate the implementation. From 926616dc88a890611bd073b21887c79dc260bc6a Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 19:24:27 +0700 Subject: [PATCH 04/41] add spec template in the right folder --- .github/{ => ISSUE_TEMPLATE}/bounty-spec-template.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => ISSUE_TEMPLATE}/bounty-spec-template.md (100%) diff --git a/.github/bounty-spec-template.md b/.github/ISSUE_TEMPLATE/bounty-spec-template.md similarity index 100% rename from .github/bounty-spec-template.md rename to .github/ISSUE_TEMPLATE/bounty-spec-template.md From 3c4daf06625b0dd028d17559018d3c6b77c0a5b6 Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 19:29:57 +0700 Subject: [PATCH 05/41] replace legacy md format with yml format --- .../ISSUE_TEMPLATE/bounty-spec-template.md | 51 ----------------- .../ISSUE_TEMPLATE/bounty-spec-template.yml | 57 +++++++++++++++++++ .github/copilot-instructions.md | 2 +- 3 files changed, 58 insertions(+), 52 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bounty-spec-template.md create mode 100644 .github/ISSUE_TEMPLATE/bounty-spec-template.yml diff --git a/.github/ISSUE_TEMPLATE/bounty-spec-template.md b/.github/ISSUE_TEMPLATE/bounty-spec-template.md deleted file mode 100644 index 7ce6aa0..0000000 --- a/.github/ISSUE_TEMPLATE/bounty-spec-template.md +++ /dev/null @@ -1,51 +0,0 @@ -# Bounty Spec Template - -Use this as the minimal starting point for a GoodBounty issue spec. - -## Context and goals - -- Why is this issue being created? -- What problem does it solve? -- How does it fit the project goals? - -## Reference: key files and features - -- Relevant files: -- Relevant features: -- Cross-repository dependencies: -- Package or dependency assumptions: - -## New components and design references - -- UX flows or screenshots: -- Core/UI components to reuse: -- New components to create: - -## Required flows - -- Required states: -- Expected behavior in each state: -- Error and empty states: - -## Execution plan - -1. Implementation: -2. Testing and validation: - -### Acceptance criteria - -Usage/demo included - -- [ ] Criterion 1 -- [ ] Criterion 2 -- [ ] Criterion 3 -- [ ] includes storybook examples and smoke tests using playwright -- [ ] includes screenshots from the different UI states and flows -- - -### Human reviewer checklist - -- [ ] Code matches the issue scope -- [ ] Required flows are implemented -- [ ] Validation steps were run -- [ ] Documentation was updated if needed diff --git a/.github/ISSUE_TEMPLATE/bounty-spec-template.yml b/.github/ISSUE_TEMPLATE/bounty-spec-template.yml new file mode 100644 index 0000000..3c75b3d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bounty-spec-template.yml @@ -0,0 +1,57 @@ +name: GoodWidget Spec Template +description: Define the requirements for a new GoodWidget +body: + - type: markdown + attributes: + value: | + # Bounty Spec Template + + Use this as the minimal starting point for a GoodBounty issue spec. + + ## Context and goals + + - Why is this issue being created? + - What problem does it solve? + - How does it fit the project goals? + + ## Reference: key files and features + + - Relevant files: + - Relevant features: + - Cross-repository dependencies: + - Package or dependency assumptions: + + ## New components and design references + + - UX flows or screenshots: + - Core/UI components to reuse: + - New components to create: + + ## Required flows + + - Required states: + - Expected behavior in each state: + - Error and empty states: + + ## Execution plan + + 1. Implementation: + 2. Testing and validation: + + ### Acceptance criteria + + Usage/demo included + + - [ ] Criterion 1 + - [ ] Criterion 2 + - [ ] Criterion 3 + - [ ] includes storybook examples and smoke tests using playwright + - [ ] includes screenshots from the different UI states and flows + - + + ### Human reviewer checklist + + - [ ] Code matches the issue scope + - [ ] Required flows are implemented + - [ ] Validation steps were run + - [ ] Documentation was updated if needed diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 9df7a2b..813260d 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -28,5 +28,5 @@ Repository overview: ## Define a GoodBounty issue spec -When asked to create or refine a GoodBounty issue make sure to follow the structure from the bounty spec template: `.github/bounty-spec-template.md` and include all the sections and details described there. Always ask for clarification if any of the sections cannot be filled with the available information or if you are not sure about any of the details. +When asked to create or refine a GoodBounty issue make sure to follow the structure from the bounty spec template: `.github/ISSUE_TEMPLATE/bounty-spec-template.yml` and include all the sections and details described there. Always ask for clarification if any of the sections cannot be filled with the available information or if you are not sure about any of the details. Be as concise as possible while still providing all the necessary information for the implementation and validation of the issue. The more clear and easy to understand the spec is, the easier it will be for the implementer to understand the requirements and for the reviewer to validate the implementation. From 8df3f1d60fdb3b0cdccba1aad98a31f564167ee8 Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 19:34:39 +0700 Subject: [PATCH 06/41] fix: github issue template has to have more fields then only markdown --- .../ISSUE_TEMPLATE/bounty-spec-template.yml | 138 ++++++++++++------ 1 file changed, 95 insertions(+), 43 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bounty-spec-template.yml b/.github/ISSUE_TEMPLATE/bounty-spec-template.yml index 3c75b3d..703c33e 100644 --- a/.github/ISSUE_TEMPLATE/bounty-spec-template.yml +++ b/.github/ISSUE_TEMPLATE/bounty-spec-template.yml @@ -8,50 +8,102 @@ body: Use this as the minimal starting point for a GoodBounty issue spec. - ## Context and goals - - - Why is this issue being created? - - What problem does it solve? - - How does it fit the project goals? - - ## Reference: key files and features - - - Relevant files: - - Relevant features: - - Cross-repository dependencies: - - Package or dependency assumptions: - - ## New components and design references - - - UX flows or screenshots: - - Core/UI components to reuse: - - New components to create: - - ## Required flows - - - Required states: - - Expected behavior in each state: - - Error and empty states: - - ## Execution plan - + - type: textarea + id: context_and_goals + attributes: + label: Context and goals + description: | + Why is this issue being created? + What problem does it solve? + How does it fit the project goals? + placeholder: | + Why is this issue being created? + What problem does it solve? + How does it fit the project goals? + validations: + required: true + + - type: textarea + id: reference_key_files_and_features + attributes: + label: Reference key files and features + description: | + Relevant files: + Relevant features: + Cross-repository dependencies: + Package or dependency assumptions: + placeholder: | + Relevant files: + Relevant features: + Cross-repository dependencies: + Package or dependency assumptions: + validations: + required: true + + - type: textarea + id: new_components_and_design_references + attributes: + label: New components and design references + description: | + UX flows or screenshots: + Core/UI components to reuse: + New components to create: + placeholder: | + UX flows or screenshots: + Core/UI components to reuse: + New components to create: + validations: + required: true + + - type: textarea + id: required_flows + attributes: + label: Required flows + description: | + Required states: + Expected behavior in each state: + Error and empty states: + placeholder: | + Required states: + Expected behavior in each state: + Error and empty states: + validations: + required: true + + - type: textarea + id: execution_plan + attributes: + label: Execution plan + description: | + 1. Implementation: + 2. Testing and validation: + placeholder: | 1. Implementation: 2. Testing and validation: + validations: + required: true + - type: markdown + attributes: + value: | ### Acceptance criteria - - Usage/demo included - - - [ ] Criterion 1 - - [ ] Criterion 2 - - [ ] Criterion 3 - - [ ] includes storybook examples and smoke tests using playwright - - [ ] includes screenshots from the different UI states and flows - - - - ### Human reviewer checklist - - - [ ] Code matches the issue scope - - [ ] Required flows are implemented - - [ ] Validation steps were run - - [ ] Documentation was updated if needed + - type: checkboxes + id: acceptance_criteria + attributes: + label: Acceptance criteria + options: + - label: Criterion 1 + - label: Criterion 2 + - label: Criterion 3 + - label: includes storybook examples and smoke tests using playwright + - label: includes screenshots from the different UI states and flows + + - type: checkboxes + id: human_reviewer_checklist + attributes: + label: Human reviewer checklist + options: + - label: Code matches the issue scope + - label: Required flows are implemented + - label: Validation steps were run + - label: Documentation was updated if needed From efdef1bfdab7da8376f269d977671a80ae50061e Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 19:55:07 +0700 Subject: [PATCH 07/41] update name and description of issue template --- ...{bounty-spec-template.yml => goodwidget-spec-template.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/ISSUE_TEMPLATE/{bounty-spec-template.yml => goodwidget-spec-template.yml} (95%) diff --git a/.github/ISSUE_TEMPLATE/bounty-spec-template.yml b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml similarity index 95% rename from .github/ISSUE_TEMPLATE/bounty-spec-template.yml rename to .github/ISSUE_TEMPLATE/goodwidget-spec-template.yml index 703c33e..6cfea06 100644 --- a/.github/ISSUE_TEMPLATE/bounty-spec-template.yml +++ b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml @@ -4,9 +4,9 @@ body: - type: markdown attributes: value: | - # Bounty Spec Template + # GoodWidget Spec Template - Use this as the minimal starting point for a GoodBounty issue spec. + define the specification for a new app, widget or UI based on GoodWidget framework - type: textarea id: context_and_goals From 4e13fb539016447216276341c082525cd8ce6965 Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 20:17:33 +0700 Subject: [PATCH 08/41] simplified template --- .../goodwidget-spec-template.yml | 98 +++---------------- 1 file changed, 16 insertions(+), 82 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml index 6cfea06..43f9ddb 100644 --- a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml +++ b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml @@ -9,101 +9,35 @@ body: define the specification for a new app, widget or UI based on GoodWidget framework - type: textarea - id: context_and_goals + id: description attributes: - label: Context and goals + label: description description: | - Why is this issue being created? + What new app, widget or UI component should be created based on the GoodWidget framework? What problem does it solve? How does it fit the project goals? placeholder: | - Why is this issue being created? + What new app, widget or UI component should be created based on the GoodWidget framework? What problem does it solve? How does it fit the project goals? validations: required: true - - type: textarea - id: reference_key_files_and_features + - type: markdown attributes: - label: Reference key files and features - description: | - Relevant files: - Relevant features: - Cross-repository dependencies: - Package or dependency assumptions: - placeholder: | - Relevant files: - Relevant features: - Cross-repository dependencies: - Package or dependency assumptions: - validations: - required: true + value: | + ### Create the plan + Update this issue description with an execution plan. - - type: textarea - id: new_components_and_design_references - attributes: - label: New components and design references - description: | - UX flows or screenshots: - Core/UI components to reuse: - New components to create: - placeholder: | - UX flows or screenshots: - Core/UI components to reuse: - New components to create: - validations: - required: true + - Map relevant files that are too be used as reference from all repos mentioned + - import existing @GoodDollar packages + - Map new components that should be created. Assess when a new component should be created in the new savings widget package or made part of the reusable packages/ui - - type: textarea - id: required_flows - attributes: - label: Required flows - description: | - Required states: - Expected behavior in each state: - Error and empty states: - placeholder: | - Required states: - Expected behavior in each state: - Error and empty states: - validations: - required: true - - - type: textarea - id: execution_plan - attributes: - label: Execution plan - description: | - 1. Implementation: - 2. Testing and validation: - placeholder: | - 1. Implementation: - 2. Testing and validation: - validations: - required: true + Plan specification required sections: - - type: markdown - attributes: - value: | - ### Acceptance criteria + - Required states, flows, and behaviors + - Execution plan + - acceptance criteria + - human-reviewer checklist - type: checkboxes id: acceptance_criteria - attributes: - label: Acceptance criteria - options: - - label: Criterion 1 - - label: Criterion 2 - - label: Criterion 3 - - label: includes storybook examples and smoke tests using playwright - - label: includes screenshots from the different UI states and flows - - - type: checkboxes - id: human_reviewer_checklist - attributes: - label: Human reviewer checklist - options: - - label: Code matches the issue scope - - label: Required flows are implemented - - label: Validation steps were run - - label: Documentation was updated if needed From 740607a38cf486d6e5eb48b697fdbd93d633ea38 Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 20:19:26 +0700 Subject: [PATCH 09/41] remove leftover type from bounty template --- .github/ISSUE_TEMPLATE/goodwidget-spec-template.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml index 43f9ddb..ee9836d 100644 --- a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml +++ b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml @@ -39,5 +39,3 @@ body: - Execution plan - acceptance criteria - human-reviewer checklist - - type: checkboxes - id: acceptance_criteria From 1532f399595eb752c838c832fe0f05850cf776be Mon Sep 17 00:00:00 2001 From: LewisB Date: Thu, 7 May 2026 20:36:31 +0700 Subject: [PATCH 10/41] fix: issue template --- .../goodwidget-spec-template.yml | 50 ++++++++++++++----- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml index ee9836d..7230793 100644 --- a/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml +++ b/.github/ISSUE_TEMPLATE/goodwidget-spec-template.yml @@ -1,25 +1,44 @@ name: GoodWidget Spec Template description: Define the requirements for a new GoodWidget body: - - type: markdown + - type: textarea + id: repos_and_packages + attributes: + label: Which repos and packages the AI should work with + description: | + List the repositories and packages the AI should work with. + value: | + List the repositories and packages the AI should work with. + validations: + required: true + + - type: textarea + id: ui_implementation_reference attributes: + label: UI implementation reference + description: | + Any of the following: + + - instruction to copy from another repo + - provide screenshots value: | - # GoodWidget Spec Template + Any of the following: - define the specification for a new app, widget or UI based on GoodWidget framework + - instruction to copy from another repo + - provide screenshots + validations: + required: true - type: textarea - id: description + id: user_flows_states_behaviours attributes: - label: description + label: User flows, states and behaviours description: | - What new app, widget or UI component should be created based on the GoodWidget framework? - What problem does it solve? - How does it fit the project goals? - placeholder: | - What new app, widget or UI component should be created based on the GoodWidget framework? - What problem does it solve? - How does it fit the project goals? + If no UI reference is given, elaborate how the UI/UX behaves. + Any other UI/UX instructions to the AI. + value: | + If no UI reference is given, elaborate how the UI/UX behaves. + Any other UI/UX instructions to the AI. validations: required: true @@ -27,7 +46,12 @@ body: attributes: value: | ### Create the plan - Update this issue description with an execution plan. + Fixed section with the following content: + + Based on the above description create an execution plan and update this issue with it while preserving the original issue content. + Do not execute the plan until given instructions to do so. + + Instructions when creating the plan: - Map relevant files that are too be used as reference from all repos mentioned - import existing @GoodDollar packages From 1efe5ea6e726b2715cc9cdf50006f24c98af2e3a Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 12:39:03 +0700 Subject: [PATCH 11/41] =?UTF-8?q?feat:=20Citizen=20SDK=20=E2=86=92=20Citiz?= =?UTF-8?q?en=20Claim=20Widget=20Migration=20(#11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: implement citizen-claim-widget with real SDK-backed adapter and UI Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/95b30966-5971-4c59-b006-9034a2a732d7 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * fix: address code review comments (wrong chain condition, ts-ignore, hex template literal) Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/95b30966-5971-4c59-b006-9034a2a732d7 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * ui primitives design gw-v2 alignment, add WidgetTabs and Anchor * - Remove 'resembling wallet-v2 claim-flow sections' - Align better and add actual wallet-v2 claim-flow sections and styling - add daily-stats and separate verification screen - Add support for sequental claiming * - add storybook demo for citizen-claim sdk with wallet-v2 design - add fixtures for testing (both injected and custodial wallets) * fix: replace missing 1.2.4 SDK exports with inline implementations using 1.2.3 primitives Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/2dad231f-36df-4f87-aa0b-679ae44e37be Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * revert: restore adapter.ts to pre-fix state (1.2.4 SDK imports intentional) Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/6d362e3c-af91-453b-9e76-db2393d308ac Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * add: local beta version of citizen-sdk * feat: Citizen SDK → Citizen Claim Widget Migration Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/b195103f-c4dd-42c8-9f1d-d5e6d5009ccc Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * test: add Playwright CitizenClaimWidget state tests + screenshots (loading, not_whitelisted, error, retry) Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/b512c917-bafa-4623-a3b5-06f0123e4db6 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * align custodial/injected stories * add: comment about private key of wallet * docs: refresh playwright screenshots for CitizenClaimWidget final review (loading, not_whitelisted, error) Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/a8f5bafd-571b-4aef-858a-f399edb25faf Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * feat: human-readable error messages in CitizenClaimWidget error state Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/18955971-cb4e-48de-b01e-72e99247383e Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * refactor: improve humanReadableError — add JSDoc, log non-Error values, sanitize revert reason Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/18955971-cb4e-48de-b01e-72e99247383e Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * fix(tests): hang RPC calls to reliably capture loading state; update loading screenshot Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/010e4445-e812-40ac-9b18-ee93af97cbd3 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * docs: add screenshot URL convention for private repos to AGENTS.md Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/3fbb4b5a-7371-4cb2-9c12-51c59cb36076 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * refactor: move CitizenClaimWidget story + screenshots to per-widget folder, update AGENTS.md Agent-Logs-Url: https://github.com/GoodDollar/GoodWidget/sessions/632dbd9c-dd10-4ea3-9daf-8388b8f8e4f8 Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> * remove test package and replace with latest release of citizen-sdk * fix: storybook stories, restructure, revert removed mockEipProvider for theme demo's --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: L03TJ3 <6606028+L03TJ3@users.noreply.github.com> Co-authored-by: LewisB --- .gitignore | 4 +- AGENTS.md | 41 ++ examples/storybook/package.json | 4 +- .../storybook/src/fixtures/mockEip1193.ts | 85 +++ .../CitizenClaimWidget.stories.tsx | 138 ++++ .../screenshots/ccw-01-loading.png | Bin 0 -> 53119 bytes .../screenshots/ccw-02-not-whitelisted.png | Bin 0 -> 55363 bytes .../screenshots/ccw-03-error.png | Bin 0 -> 55303 bytes .../{ => design-system}/Card.stories.tsx | 0 .../ClaimWidget.stories.tsx | 6 +- .../{ => design-system}/Drawer.stories.tsx | 0 .../{ => design-system}/GlowCard.stories.tsx | 0 .../ThemePlayground.stories.tsx | 12 +- .../TokenAmount.stories.tsx | 0 packages/citizen-claim-widget/package.json | 21 +- .../src/CitizenClaimWidget.tsx | 559 ++++++++++++++++ packages/citizen-claim-widget/src/adapter.ts | 610 ++++++++++++++++++ packages/citizen-claim-widget/src/element.ts | 26 + packages/citizen-claim-widget/src/index.ts | 10 + .../citizen-claim-widget/src/integration.ts | 4 +- packages/citizen-claim-widget/src/register.ts | 27 + .../src/widgetRuntimeContract.ts | 34 +- packages/citizen-claim-widget/tsup.config.ts | 2 + .../src/ClaimWidget.tsx | 208 +++--- .../tsconfig.build.json | 1 + packages/ui/src/components/Heading.ts | 2 +- packages/ui/src/components/Text.ts | 7 +- packages/ui/src/components/TokenAmount.tsx | 43 +- packages/ui/src/index.ts | 2 + packages/ui/src/presets.ts | 2 + playwright.config.ts | 11 +- pnpm-lock.yaml | 340 ++++++++++ tests/demo/citizen-claim-widget.spec.ts | 166 +++++ 33 files changed, 2218 insertions(+), 147 deletions(-) create mode 100644 examples/storybook/src/fixtures/mockEip1193.ts create mode 100644 examples/storybook/src/stories/citizen-claim-widget/CitizenClaimWidget.stories.tsx create mode 100644 examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-01-loading.png create mode 100644 examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-02-not-whitelisted.png create mode 100644 examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-03-error.png rename examples/storybook/src/stories/{ => design-system}/Card.stories.tsx (100%) rename examples/storybook/src/stories/{ => design-system}/ClaimWidget.stories.tsx (94%) rename examples/storybook/src/stories/{ => design-system}/Drawer.stories.tsx (100%) rename examples/storybook/src/stories/{ => design-system}/GlowCard.stories.tsx (100%) rename examples/storybook/src/stories/{ => design-system}/ThemePlayground.stories.tsx (94%) rename examples/storybook/src/stories/{ => design-system}/TokenAmount.stories.tsx (100%) create mode 100644 packages/citizen-claim-widget/src/CitizenClaimWidget.tsx create mode 100644 packages/citizen-claim-widget/src/adapter.ts create mode 100644 packages/citizen-claim-widget/src/element.ts create mode 100644 packages/citizen-claim-widget/src/register.ts create mode 100644 tests/demo/citizen-claim-widget.spec.ts diff --git a/.gitignore b/.gitignore index 5136538..b6eedd1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ coverage/ .codex test-results/ playwright-report/ -**/storybook-static/ \ No newline at end of file +**/storybook-static/ +**/.yalc +**/yalc.lock \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 94e484d..9e2ec03 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,6 +50,13 @@ GoodWidget/ react-web/ # React web demo html/ # plain HTML web-component demo expo/ # Expo / React Native demo + storybook/ + src/ + stories/ + / # one subfolder per widget + *.stories.tsx + screenshots/ # committed Playwright evidence PNGs + design-system/ # stories not tied to a specific widget docs/ PACKAGING.md # packaging and distribution guide demo-environment.md # Storybook, Playwright, demo routes, fixtures @@ -120,6 +127,40 @@ GoodWidget/ --- +## Playwright Screenshots + +### Where screenshots live + +Each widget's Playwright screenshots are stored **inside the widget's story folder**: + +``` +examples/storybook/src/stories//screenshots/ +``` + +For example, `CitizenClaimWidget` screenshots live at: + +``` +examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-01-loading.png +examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-02-not-whitelisted.png +examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-03-error.png +``` + +The Playwright spec writes screenshots directly to these paths so that running +`pnpm test:demo` automatically keeps the committed files up to date. + +### PR requirements for screenshot evidence + +1. **Always include the latest screenshots in the PR description** that triggered the + Playwright test run. Embed them as inline images so reviewers can verify the UI without + checking out the branch. +2. **Re-run Playwright and update the PR description** every time screenshots are regenerated + (e.g. after a UI fix or a new test was added). +3. Do not use `raw.githubusercontent.com` or `github.com/blob/…?raw=true` for inline images + in PR descriptions — use the GitHub attachment CDN (`user-attachments/assets/…`) URLs + generated by uploading via the GitHub web UI. + +--- + ## Reference Routing Use the right document for each type of task: diff --git a/examples/storybook/package.json b/examples/storybook/package.json index 044f9aa..25373c9 100644 --- a/examples/storybook/package.json +++ b/examples/storybook/package.json @@ -12,9 +12,11 @@ "@goodwidget/core": "workspace:*", "@goodwidget/ui": "workspace:*", "@goodwidget/claim-widget-theme-demo": "workspace:*", + "@goodwidget/citizen-claim-widget": "workspace:*", "react": "^18.3.0", "react-dom": "^18.3.0", - "react-native-web": "^0.19.13" + "react-native-web": "^0.19.13", + "viem": "^2.0.0" }, "devDependencies": { "@storybook/addon-essentials": "^8.6.17", diff --git a/examples/storybook/src/fixtures/mockEip1193.ts b/examples/storybook/src/fixtures/mockEip1193.ts new file mode 100644 index 0000000..d4bd906 --- /dev/null +++ b/examples/storybook/src/fixtures/mockEip1193.ts @@ -0,0 +1,85 @@ +/** + * Mock EIP-1193 provider for demo and Playwright testing purposes. + * + * This provider simulates a connected wallet with a stable, deterministic + * address and chain ID so demo pages render wallet-aware components in a + * "connected" state without requiring a real browser wallet. + * + * It is ONLY used in the storybook demo (`examples/storybook/src/fixtures/`). + * It does NOT simulate real transaction signing or RPC calls. + * + * Stable demo values: + * address : 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 (well-known demo address) + * chainId : 42220 (Celo mainnet — GoodDollar's primary chain) + */ + +/** The deterministic demo wallet address. */ +export const MOCK_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' + +/** The deterministic demo chain ID (Celo mainnet). */ +export const MOCK_CHAIN_ID = 42220 + +// Converts a number to a 0x-prefixed hex string as required by the EIP-1193 spec. +function toHex(n: number): string { + return '0x' + n.toString(16) +} + +type EventCallback = (...args: unknown[]) => void + +/** + * Creates a minimal EIP-1193-compatible provider that always reports the + * demo address and chain. Used to pass as the `provider` prop to + * `GoodWidgetProvider` so wallet-aware components render in a connected state. + * + * @example + * ```tsx + * import { createMockEip1193Provider } from '../fixtures/mockEip1193' + * + * + * + * + * ``` + */ +export function createMockEip1193Provider() { + // Internal event-listener registry (mimics EventEmitter interface on providers) + const listeners: Record = {} + + return { + // ------------------------------------------------------------------ events + on(event: string, fn: EventCallback) { + if (!listeners[event]) listeners[event] = [] + listeners[event].push(fn) + }, + + removeListener(event: string, fn: EventCallback) { + if (!listeners[event]) return + listeners[event] = listeners[event].filter((cb) => cb !== fn) + }, + + // ----------------------------------------------------------------- request + /** + * Handles a subset of EIP-1193 JSON-RPC methods needed to put the app + * in a "wallet connected" state. Unsupported methods reject so the + * provider behaves honestly rather than silently swallowing errors. + */ + async request({ method }: { method: string }): Promise { + switch (method) { + // Return the single mock account + case 'eth_accounts': + case 'eth_requestAccounts': + return [MOCK_ADDRESS] + + // Return the chain ID in 0x-hex format (EIP-1193 spec) + case 'eth_chainId': + return toHex(MOCK_CHAIN_ID) + + // net_version returns chain ID as a decimal string + case 'net_version': + return String(MOCK_CHAIN_ID) + + default: + throw new Error(`Mock provider: unsupported method "${method}"`) + } + }, + } +} diff --git a/examples/storybook/src/stories/citizen-claim-widget/CitizenClaimWidget.stories.tsx b/examples/storybook/src/stories/citizen-claim-widget/CitizenClaimWidget.stories.tsx new file mode 100644 index 0000000..de60e31 --- /dev/null +++ b/examples/storybook/src/stories/citizen-claim-widget/CitizenClaimWidget.stories.tsx @@ -0,0 +1,138 @@ +import React, { useEffect, useState } from 'react' +import type { Meta, StoryObj } from '@storybook/react' +import { Card, Text, WidgetTabs, YStack } from '@goodwidget/ui' +import { CitizenClaimWidget } from '@goodwidget/citizen-claim-widget' +import { + getInjectedEip1193Provider, + isInjectedProviderUsable, +} from '../../fixtures/injectedEip1193' +import { createCustodialEip1193Provider } from '../../fixtures/custodialEip1193' + +type CitizenClaimTab = 'claim' | 'invite-rewards' | 'news-feed' + +function CitizenClaimWidgetStoryShell({ + provider, + dataTestId, +}: { + provider: unknown + dataTestId: string +}) { + const [activeTab, setActiveTab] = useState('claim') + const [activeChainId, setActiveChainId] = useState(null) + + useEffect(() => { + const eip1193Provider = provider as { + request?: (args: { method: string }) => Promise + on?: (event: string, listener: (value: unknown) => void) => void + removeListener?: (event: string, listener: (value: unknown) => void) => void + } | null + + if (!eip1193Provider?.request) return + + const syncChain = async () => { + const hex = (await eip1193Provider.request?.({ method: 'eth_chainId' })) as string + if (typeof hex === 'string') setActiveChainId(parseInt(hex, 16)) + } + + const onChainChanged = (hex: unknown) => { + if (typeof hex === 'string') setActiveChainId(parseInt(hex, 16)) + } + + void syncChain() + eip1193Provider.on?.('chainChanged', onChainChanged) + return () => eip1193Provider.removeListener?.('chainChanged', onChainChanged) + }, [provider]) + + return ( + + {/* ------------------------------------------------------------------ */} + {/* Header */} + {/* ------------------------------------------------------------------ */} + setActiveTab(tabId as CitizenClaimTab)} + chainId={activeChainId ?? 42220} + /> + + {activeTab === 'claim' ? ( + + ) : ( + + + Widget coming soon + + + )} + + ) +} + +const meta: Meta = { + title: 'Widgets/CitizenClaimWidget', + component: CitizenClaimWidget, + tags: ['autodocs'], + parameters: { layout: 'padded' }, +} + +export default meta +type Story = StoryObj + +function InjectedWalletStory() { + const injectedProvider = getInjectedEip1193Provider() + const usableProvider = isInjectedProviderUsable(injectedProvider) + + if (!usableProvider) { + return ( + + No injected wallet found + + Install/enable MetaMask (or another EIP-1193 wallet) in this browser, then refresh + Storybook. + + + ) + } + + return ( + + ) +} + +function CustodialLocalFixtureStory() { + try { + const provider = createCustodialEip1193Provider() + return ( + + ) + } catch (error: unknown) { + return ( + + Custodial fixture not configured + + {error instanceof Error + ? error.message + : 'Set a local private key in custodialEip1193.ts'} + + + ) + } +} + +export const InjectedWallet: Story = { + render: () => , +} + +export const CustodialLocalFixture: Story = { + render: () => , +} diff --git a/examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-01-loading.png b/examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-01-loading.png new file mode 100644 index 0000000000000000000000000000000000000000..0a70f20ca06ec86bb3d60f47e87f427216fe5ffd GIT binary patch literal 53119 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
  • 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 L5HEZG+3&vr8uSil literal 0 HcmV?d00001 diff --git a/examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-03-error.png b/examples/storybook/src/stories/citizen-claim-widget/screenshots/ccw-03-error.png new file mode 100644 index 0000000000000000000000000000000000000000..5d1a554f6ab785e3dfcfd1a271a242f6ce5abe54 GIT binary patch literal 55303 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 = { - title: 'Widgets/ClaimWidget', + title: 'Theme/ClaimWidgetThemeDemo', component: ClaimWidget, tags: ['autodocs'], parameters: { layout: 'padded' }, diff --git a/examples/storybook/src/stories/Drawer.stories.tsx b/examples/storybook/src/stories/design-system/Drawer.stories.tsx similarity index 100% rename from examples/storybook/src/stories/Drawer.stories.tsx rename to examples/storybook/src/stories/design-system/Drawer.stories.tsx diff --git a/examples/storybook/src/stories/GlowCard.stories.tsx b/examples/storybook/src/stories/design-system/GlowCard.stories.tsx similarity index 100% rename from examples/storybook/src/stories/GlowCard.stories.tsx rename to examples/storybook/src/stories/design-system/GlowCard.stories.tsx diff --git a/examples/storybook/src/stories/ThemePlayground.stories.tsx b/examples/storybook/src/stories/design-system/ThemePlayground.stories.tsx similarity index 94% rename from examples/storybook/src/stories/ThemePlayground.stories.tsx rename to examples/storybook/src/stories/design-system/ThemePlayground.stories.tsx index bb9d846..8e84af2 100644 --- a/examples/storybook/src/stories/ThemePlayground.stories.tsx +++ b/examples/storybook/src/stories/design-system/ThemePlayground.stories.tsx @@ -13,9 +13,9 @@ */ import React from 'react' import type { Meta, StoryObj } from '@storybook/react' -import { ClaimWidget } from '@goodwidget/claim-widget' +import { ClaimWidget } from '@goodwidget/claim-widget-theme-demo' import { Card, Heading, Text, Alert, YStack } from '@goodwidget/ui' -import { createMockEip1193Provider } from '../fixtures/mockEip1193' +import { createMockEip1193Provider } from '../../fixtures/mockEip1193' const mockProvider = createMockEip1193Provider() @@ -165,7 +165,9 @@ export const HostOverrideCobalt: Story = { =18.0.0" }, "dependencies": { + "@goodsdks/citizen-sdk": "1.2.5", "@goodwidget/core": "workspace:*", - "@goodwidget/ui": "workspace:*" + "@goodwidget/embed": "workspace:*", + "@goodwidget/ui": "workspace:*", + "viem": "^2.0.0" }, "devDependencies": { - "react": "^18.3.0", - "react-dom": "^18.3.0", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "react": "^18.3.0", + "react-dom": "^18.3.0", "tsup": "^8.4.0", "typescript": "^5.7.0" } diff --git a/packages/citizen-claim-widget/src/CitizenClaimWidget.tsx b/packages/citizen-claim-widget/src/CitizenClaimWidget.tsx new file mode 100644 index 0000000..783f5a0 --- /dev/null +++ b/packages/citizen-claim-widget/src/CitizenClaimWidget.tsx @@ -0,0 +1,559 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react' +import { GoodWidgetProvider } from '@goodwidget/core' +import type { EIP1193Provider } from '@goodwidget/core' +import { + createComponent, + Card, + Heading, + Text, + Anchor, + Button, + ButtonFrame, + ButtonText, + TokenAmount, + Spinner, + Separator, + ToastContainer, + createToast, + updateToast, + XStack, + YStack, +} from '@goodwidget/ui' +import { SupportedChains } from '@goodsdks/citizen-sdk' +import { useCitizenClaimAdapter } from './adapter' +import type { + CitizenClaimWidgetProps, + CitizenClaimWidgetSuccessDetail, + CitizenClaimWidgetErrorDetail, + CitizenClaimWidgetEnvironment, +} from './widgetRuntimeContract' + +// --------------------------------------------------------------------------- +// Named styled components — these participate in the component sub-theme system. +// Integrators can override light_ClaimCard, dark_ClaimCard etc. in themeOverrides. +// --------------------------------------------------------------------------- + +/** Primary card wrapping the claim amount and action button. */ +const ClaimCard = createComponent(Card, { + name: 'ClaimCard', + extends: 'Card', + borderRadius: '$4', + padding: '$4', +}) + +/** Circular action button that mirrors the GoodWalletV2 claim button design. */ +const ClaimActionButton = createComponent(ButtonFrame, { + name: 'ClaimActionButton', + extends: 'Button', + width: 160, + height: 160, + borderRadius: 9999, + backgroundColor: '$backgroundTransparent', + borderWidth: 0, + shadowOpacity: 0, + overflow: 'visible' as const, + position: 'relative' as const, + paddingHorizontal: 0, + hoverStyle: { backgroundColor: '$backgroundTransparent' }, + pressStyle: { backgroundColor: '$backgroundTransparent', opacity: 0.95 }, + focusStyle: { backgroundColor: '$backgroundTransparent', outlineStyle: 'none' }, +}) + +/** Blurred halo glow layer behind the action ring. */ +const ClaimActionGlow = createComponent(YStack, { + name: 'ClaimActionGlow', + position: 'absolute' as const, + top: -16, + right: -16, + bottom: -16, + left: -16, + borderRadius: 9999, + backgroundColor: '$primary', + opacity: 0.45, +}) + +/** Solid ring forming the outer rim of the action button. */ +const ClaimActionRing = createComponent(YStack, { + name: 'ClaimActionRing', + position: 'absolute' as const, + top: 0, + right: 0, + bottom: 0, + left: 0, + borderRadius: 9999, + backgroundColor: '$primary', +}) + +/** Dark inner circle inside the action ring. */ +const ClaimActionInner = createComponent(YStack, { + name: 'ClaimActionInner', + position: 'absolute' as const, + top: 2, + right: 2, + bottom: 2, + left: 2, + borderRadius: 9999, + backgroundColor: '$backgroundDark', +}) + +/** Vertical container for the per-chain claim breakdown area. */ +const ClaimChainBreakdown = createComponent(YStack, { + name: 'ClaimChainBreakdown', + alignItems: 'center' as const, + gap: '$2', +}) + +/** Row wrapping all chain entries (allows wrapping on smaller widths). */ +const ClaimChainList = createComponent(XStack, { + name: 'ClaimChainList', + flexWrap: 'wrap' as const, + justifyContent: 'center' as const, + alignItems: 'center' as const, + columnGap: '$2', + rowGap: '$1', + paddingHorizontal: '$4', +}) + +/** Single chain entry: amount + chain label (+ separator rendered externally). */ +const ClaimChainItem = createComponent(XStack, { + name: 'ClaimChainItem', + alignItems: 'center' as const, + gap: '$1', +}) + +/** Footer wrapper for daily claim stats block. */ +const ClaimDailyStats = createComponent(YStack, { + name: 'ClaimDailyStats', + alignItems: 'center' as const, + gap: '$1', + paddingTop: '$3', +}) + +/** Single centered stats row (matches GoodWalletV2 footer row behavior). */ +const ClaimDailyStatsRow = createComponent(Text, { + name: 'ClaimDailyStatsRow', + width: '100%' as const, + justifyContent: 'center' as const, + alignItems: 'center' as const, + gap: '$2', + display: 'flex' as const, +}) + +function getChainName(chainId: number): string { + switch (chainId) { + case SupportedChains.FUSE: + return 'Fuse' + case SupportedChains.CELO: + return 'Celo' + case SupportedChains.XDC: + return 'XDC' + default: + return `Chain ${chainId}` + } +} + +function formatCompactNumber(value: number): string { + return new Intl.NumberFormat('en-US', { + style: 'decimal', + minimumFractionDigits: 0, + maximumFractionDigits: 2, + useGrouping: true, + notation: 'compact', + }).format(value) +} + +// --------------------------------------------------------------------------- +// Countdown — shows HH:MM:SS until the next claimable period. +// --------------------------------------------------------------------------- +function Countdown({ nextClaim }: { nextClaim: Date }) { + const getTimeLeft = () => Math.max(0, Math.floor((nextClaim.getTime() - Date.now()) / 1000)) + const [timeLeft, setTimeLeft] = useState(getTimeLeft) + + useEffect(() => { + const id = setInterval(() => setTimeLeft(getTimeLeft()), 1000) + return () => clearInterval(id) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [nextClaim]) + + const h = Math.floor(timeLeft / 3600) + .toString() + .padStart(2, '0') + const m = Math.floor((timeLeft % 3600) / 60) + .toString() + .padStart(2, '0') + const s = (timeLeft % 60).toString().padStart(2, '0') + + return <>{`${h}:${m}:${s}`} +} + +// --------------------------------------------------------------------------- +// Inner component — must live inside GoodWidgetProvider so it can use useWallet. +// --------------------------------------------------------------------------- +interface CitizenClaimInnerProps { + environment?: CitizenClaimWidgetEnvironment + walletMode: 'custodial' | 'injected' + onClaimSuccess?: (detail: CitizenClaimWidgetSuccessDetail) => void + onClaimError?: (detail: CitizenClaimWidgetErrorDetail) => void +} + +function CitizenClaimInner({ + environment, + walletMode, + onClaimSuccess, + onClaimError, +}: CitizenClaimInnerProps) { + const { state, actions } = useCitizenClaimAdapter({ environment }) + const { + status, + address, + chainId, + amount, + primaryAction, + primaryLabel, + error, + nextClaimTime, + claimablesByChain, + dailyStats, + } = state + + const isPending = status === 'claiming' || status === 'loading' || status === 'connecting' + const totalClaimableAmount = claimablesByChain.reduce( + (sum, item) => sum + (Number.parseFloat(item.amount) || 0), + 0, + ) + const displayAmount = claimablesByChain.length > 0 ? totalClaimableAmount.toFixed(2) : amount + const chainNameById = useMemo(() => { + const map = new Map() + for (const entry of claimablesByChain) { + map.set(entry.chainId, getChainName(entry.chainId)) + } + return map + }, [claimablesByChain]) + + /** Dispatch the primary action and surface callbacks for claim outcomes. */ + const handlePrimaryAction = useCallback(async () => { + try { + switch (primaryAction) { + case 'connect': + await actions.connect() + break + case 'verify': + await actions.startVerification() + break + case 'claim': { + const claimPlan = [...claimablesByChain] + if (claimPlan.length === 0) { + const singleChainName = chainId ? getChainName(chainId) : 'active chain' + const toastId = createToast({ + message: `Claim initiated on ${singleChainName}`, + status: 'pending', + duration: 0, + }) + + try { + const receipt = await actions.claim() + updateToast(toastId, { + message: `Claim succeeded on ${singleChainName}`, + status: 'success', + duration: 3200, + }) + onClaimSuccess?.({ + address: address!, + chainId: chainId!, + transactionHash: (receipt as { transactionHash?: string } | undefined) + ?.transactionHash, + }) + } catch (singleClaimError: unknown) { + updateToast(toastId, { + message: `Claim failed on ${singleChainName}`, + status: 'error', + duration: 0, + }) + onClaimError?.({ + address: address ?? null, + chainId: chainId ?? null, + message: + singleClaimError instanceof Error ? singleClaimError.message : 'Claim failed', + }) + } + break + } + + for (const claimEntry of claimPlan) { + const entryChainName = + chainNameById.get(claimEntry.chainId) ?? getChainName(claimEntry.chainId) + const toastId = createToast({ + message: `Claim initiated on ${entryChainName}`, + status: 'pending', + duration: 0, + }) + + try { + const receipt = await actions.claimOnChain(claimEntry.chainId) + updateToast(toastId, { + message: `Claim succeeded on ${entryChainName}`, + status: 'success', + duration: 3200, + }) + onClaimSuccess?.({ + address: address!, + chainId: claimEntry.chainId, + transactionHash: (receipt as { transactionHash?: string } | undefined) + ?.transactionHash, + }) + } catch (multiClaimError: unknown) { + updateToast(toastId, { + message: `Claim failed on ${entryChainName}`, + status: 'error', + duration: 0, + }) + onClaimError?.({ + address: address ?? null, + chainId: claimEntry.chainId, + message: + multiClaimError instanceof Error ? multiClaimError.message : 'Claim failed', + }) + } finally { + } + } + + await actions.refresh() + break + } + case 'refresh': + await actions.refresh() + break + case 'switch_chain': + // Default to Celo (42220) as the first preferred supported chain + await actions.switchChain?.(42220) + break + } + } catch (err: unknown) { + if (primaryAction === 'claim') { + onClaimError?.({ + address: address ?? null, + chainId: chainId ?? null, + message: err instanceof Error ? err.message : 'Claim failed', + }) + } + } + }, [ + primaryAction, + actions, + address, + chainId, + chainNameById, + claimablesByChain, + onClaimSuccess, + onClaimError, + ]) + + return ( + + {status === 'not_whitelisted' && ( + + + + Whitelisting Required + + + Face verification is required before you can claim. + + + + We take your privacy seriously. We only store some particularities/relief data in our + database, not the photo of your face itself.{' '} + + Learn more + + + )} + {/* ------------------------------------------------------------------ */} + {/* Main claim card */} + {/* ------------------------------------------------------------------ */} + {status !== 'not_whitelisted' && ( + + + {/* Status content */} + + {status === 'loading' && } + + {status === 'not_connected' && ( + <> + Connect your wallet to claim daily G$ + + )} + + {(status === 'eligible' || status === 'claiming') && ( + <> + Ready to claim + {displayAmount && } + + )} + + {status === 'success' && ( + + Claimed successfully! 🎉 + + )} + + {status === 'already_claimed' && ( + <> + Just a little longer… + More G$ coming soon + + )} + + {status === 'error' && error && ( + + {error} + + )} + + + {status !== 'loading' && claimablesByChain.length > 0 && ( + + + {claimablesByChain.map((entry, index) => ( + + + {getChainName(entry.chainId)} + {index < claimablesByChain.length - 1 && ( + + · + + )} + + ))} + + + )} + + {/* Action button — shown whenever there is a meaningful primary action */} + {primaryAction !== 'none' && ( + + + {/* Blurred glow halo matching GoodWalletV2 claim button */} + + + + + + {isPending ? ( + + {primaryLabel} + + + ) : ( + {primaryLabel} + )} + + + + )} + + + )} + + {/* ------------------------------------------------------------------ */} + {/* Next-claim footer (already_claimed state) */} + {/* ------------------------------------------------------------------ */} + {status === 'already_claimed' && nextClaimTime && ( + + + + Next claim in + + + + + + + Your UBI resets each day. Come back when the timer ends. + + + + )} + + + + Today + + + {formatCompactNumber(dailyStats.dailyNumberOfClaimers)}{' '} + claimers received + + + + + ) +} + +// --------------------------------------------------------------------------- +// Public component +// --------------------------------------------------------------------------- + +/** + * CitizenClaimWidget — real SDK-backed GoodDollar UBI claim flow. + * + * Aligned to GoodWalletV2 claim behavior and the claim-widget-theme-demo visual baseline. + * + * Usage as a React component: + * + * + * Also available as a Web Component via the `element` or `register` entry points. + * + * Provider-first runtime path: + * host provider → GoodWidgetProvider → citizen-claim adapter → citizen-sdk + */ +export function CitizenClaimWidget({ + provider, + environment = 'production', + themeOverrides, + config, + defaultTheme = 'light', + onClaimSuccess, + onClaimError, +}: CitizenClaimWidgetProps) { + const walletMode = + provider && + typeof provider === 'object' && + (provider as { __gwWalletMode?: string }).__gwWalletMode === 'custodial' + ? 'custodial' + : 'injected' + + return ( + + + + + ) +} diff --git a/packages/citizen-claim-widget/src/adapter.ts b/packages/citizen-claim-widget/src/adapter.ts new file mode 100644 index 0000000..4a0b7c3 --- /dev/null +++ b/packages/citizen-claim-widget/src/adapter.ts @@ -0,0 +1,610 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useWallet } from '@goodwidget/core' +import { createPublicClient, createWalletClient, custom, formatUnits, http, type Chain } from 'viem' +import { + ClaimSDK, + IdentitySDK, + citizenSdkCapabilities, + checkGenericDailyStats, + checkGenericEntitlement, + isSupportedChain, + SupportedChains, + CHAIN_DECIMALS, +} from '@goodsdks/citizen-sdk' +import type { + CitizenClaimWidgetAdapterActions, + CitizenClaimWidgetAdapterResult, + CitizenClaimWidgetAdapterState, + CitizenClaimWidgetEnvironment, + CitizenClaimWidgetStatus, +} from './widgetRuntimeContract' + +// --------------------------------------------------------------------------- +// Minimal viem chain descriptors for the 3 chains supported by citizen-sdk. +// These are required so walletClient.chain?.id resolves correctly for the SDK. +// --------------------------------------------------------------------------- +const CHAIN_CONFIGS: Record = { + [SupportedChains.FUSE]: { + id: SupportedChains.FUSE, + name: 'Fuse', + nativeCurrency: { name: 'Fuse', symbol: 'FUSE', decimals: 18 }, + rpcUrls: { default: { http: ['https://rpc.fuse.io'] } }, + } as Chain, + [SupportedChains.CELO]: { + id: SupportedChains.CELO, + name: 'Celo', + nativeCurrency: { name: 'Celo', symbol: 'CELO', decimals: 18 }, + rpcUrls: { default: { http: ['https://forno.celo.org'] } }, + } as Chain, + [SupportedChains.XDC]: { + id: SupportedChains.XDC, + name: 'XDC Network', + nativeCurrency: { name: 'XDC', symbol: 'XDC', decimals: 18 }, + rpcUrls: { default: { http: ['https://rpc.ankr.com/xdc'] } }, + } as Chain, +} + +const SUPPORTED_CHAINS = citizenSdkCapabilities.chains +const AVAILABLE_ENVIRONMENTS = citizenSdkCapabilities.environments + +// --------------------------------------------------------------------------- +// humanReadableError — converts a raw SDK/viem error into a short, user-friendly +// string. The full technical error is always logged to the console for debugging. +// --------------------------------------------------------------------------- +/** + * Maps a raw error (viem RPC error, network failure, contract revert, etc.) to a + * short, human-readable string suitable for display in the widget UI. + * + * The full error is always logged to `console.error` so it remains available for + * debugging without cluttering the user-facing card. + * + * @param err - The caught error value (may be any type). + * @returns A concise, user-friendly error string. + */ +function humanReadableError(err: unknown): string { + console.error('[CitizenClaimWidget]', err) + + if (!(err instanceof Error)) { + // Log the raw value so non-Error throws are still traceable + console.error('[CitizenClaimWidget] non-Error thrown:', typeof err, err) + return 'Something went wrong. Please try again.' + } + + const msg = err.message + + // Network-level failures (fetch failed, connection refused, etc.) + if ( + msg.includes('Failed to fetch') || + msg.includes('HTTP request failed') || + msg.includes('fetch failed') || + msg.includes('NetworkError') || + msg.includes('net::ERR_') || + msg.includes('ECONNREFUSED') || + msg.includes('ECONNRESET') || + msg.includes('ETIMEDOUT') + ) { + return 'Unable to reach the network. Check your connection and try again.' + } + + // Timeout + if (msg.includes('timeout') || msg.includes('Timeout') || msg.includes('timed out')) { + return 'The request timed out. Please try again.' + } + + // User rejected transaction + if ( + msg.includes('User rejected') || + msg.includes('user rejected') || + msg.includes('4001') || + msg.includes('ACTION_REJECTED') + ) { + return 'Transaction rejected by wallet.' + } + + // Insufficient funds + if (msg.includes('insufficient funds') || msg.includes('InsufficientFunds')) { + return 'Insufficient funds to complete this transaction.' + } + + // Contract revert — try to extract just the revert reason + if (msg.includes('reverted') || msg.includes('revert')) { + const reasonMatch = msg.match(/reason:\s*(.+?)(?:\n|$)/) + if (reasonMatch) { + // Sanitize: strip control characters and cap length to avoid injection/overflow + const reason = reasonMatch[1].replace(/[^\x20-\x7E]/g, '').trim().slice(0, 80) + if (reason) { + return `Transaction failed: ${reason}` + } + } + return 'Transaction was reverted. Please try again.' + } + + // Unsupported chain + if (msg.includes('unsupported chain') || msg.includes('Unsupported chain')) { + return 'This network is not supported. Please switch to a supported chain.' + } + + return 'Something went wrong. Please try again.' +} + +export interface UseCitizenClaimAdapterOptions { + environment?: CitizenClaimWidgetEnvironment + /** + * URL to redirect the user to after face-verification completes. + * Defaults to the current page URL if running in a browser. + */ + rdu?: string +} + +type CitizenEnvironment = 'production' | 'staging' | 'development' + +/** + * Core adapter hook: bridges @goodsdks/citizen-sdk to GoodWidget state/actions. + * + * Runtime path: + * host provider → GoodWidgetProvider → useWallet() → this adapter → citizen-sdk + * + * The adapter: + * 1. Reads wallet state from useWallet() (injected by GoodWidgetProvider) + * 2. Creates viem public/wallet clients from the EIP1193 provider + * 3. Instantiates IdentitySDK + ClaimSDK from those clients + * 4. Manages the CitizenClaimWidgetStatus state machine + * 5. Exposes typed actions: connect, verify, claim, refresh, switchChain + * + * State transitions (mirrors GoodWalletV2 ClaimView.tsx logic): + * not_connected → [connect] → loading + * loading → not_whitelisted | eligible | already_claimed | error + * not_whitelisted → [verify] → (external FV flow) → loading after return + * eligible → [claim] → claiming → success | error + * error → [refresh] → loading + */ +export function useCitizenClaimAdapter( + options: UseCitizenClaimAdapterOptions = {}, +): CitizenClaimWidgetAdapterResult { + const { address, chainId, isConnected, provider, connect } = useWallet() + + // Normalise env string to one of the SDK-declared runtime environments. + const env = ( + options.environment && AVAILABLE_ENVIRONMENTS.includes(options.environment) + ? options.environment + : 'production' + ) as CitizenEnvironment + + // Whether the connected wallet is on a chain supported by citizen-sdk + const onSupportedChain = chainId !== null && isSupportedChain(chainId) + + const [status, setStatus] = useState( + isConnected ? 'loading' : 'not_connected', + ) + const [amount, setAmount] = useState(null) + const [nextClaimTime, setNextClaimTime] = useState(null) + const [error, setError] = useState(null) + const [claimablesByChain, setClaimablesByChain] = useState< + Array<{ chainId: number; amount: string }> + >([]) + const [dailyStats, setDailyStats] = useState({ + dailyNumberOfClaimers: 0, + dailyClaimedAmount: 0, + }) + + // Guard against state updates after the component unmounts + const mountedRef = useRef(true) + useEffect(() => { + mountedRef.current = true + return () => { + mountedRef.current = false + } + }, []) + + // --------------------------------------------------------------------------- + // Client factory — creates viem clients from the EIP1193 provider. + // Returns null when any required wallet state is missing. + // --------------------------------------------------------------------------- + const createClientsForChain = useCallback( + (targetChainId: number) => { + if (!provider || !address) return null + const chain = CHAIN_CONFIGS[targetChainId] + if (!chain) return null + const transport = custom(provider as Parameters[0]) + const publicClient = createPublicClient({ chain, transport }) + const walletClient = createWalletClient({ + account: address as `0x${string}`, + chain, + transport, + }) + return { publicClient, walletClient } + }, + [provider, address], + ) + + const createClients = useCallback(() => { + if (!chainId) return null + if (!provider || !address) return null + const chain = CHAIN_CONFIGS[chainId] + if (!chain) return null + // chain may be undefined for unsupported networks; the SDK will throw clearly. + const transport = custom(provider as Parameters[0]) + const publicClient = createPublicClient({ chain, transport }) + const walletClient = createWalletClient({ + account: address as `0x${string}`, + chain, + transport, + }) + return { publicClient, walletClient } + }, [provider, address, chainId]) + + // --------------------------------------------------------------------------- + // SDK factory — wraps viem clients in IdentitySDK + ClaimSDK instances. + // --------------------------------------------------------------------------- + const createSdkInstances = useCallback( + (clients: ReturnType) => { + if (!clients || !address) return null + const { publicClient, walletClient } = clients + const identitySDK = new IdentitySDK({ publicClient, walletClient, env }) + const claimSDK = new ClaimSDK({ + account: address as `0x${string}`, + publicClient, + walletClient, + identitySDK, + env, + // Return URL used by the GoodID face-verification redirect flow + rdu: options.rdu ?? (typeof window !== 'undefined' ? window.location.href : ''), + }) + return { identitySDK, claimSDK } + }, + [address, env, options.rdu], + ) + + const createSdkInstancesForChain = useCallback( + (targetChainId: number) => { + const clients = createClientsForChain(targetChainId) + if (!clients || !address) return null + const { publicClient, walletClient } = clients + const identitySDK = new IdentitySDK({ publicClient, walletClient, env }) + const claimSDK = new ClaimSDK({ + account: address as `0x${string}`, + publicClient, + walletClient, + identitySDK, + env, + rdu: options.rdu ?? (typeof window !== 'undefined' ? window.location.href : ''), + }) + return { identitySDK, claimSDK } + }, + [createClientsForChain, address, env, options.rdu], + ) + + /** + * Collects claimable UBI amounts for all citizen-sdk supported chains. + * This mirrors GoodWalletV2's claim breakdown model (eligible amounts per chain). + */ + const loadClaimablesByChain = useCallback(async (): Promise => { + const eligible: Array<{ chainId: number; amount: string }> = [] + + await Promise.all( + SUPPORTED_CHAINS.map(async (supportedChainId) => { + try { + const chain = CHAIN_CONFIGS[supportedChainId] + const rpcUrl = chain.rpcUrls.default.http[0] + if (!rpcUrl) return + const publicClient = createPublicClient({ chain, transport: http(rpcUrl) }) + const entitlement = await checkGenericEntitlement({ + publicClient, + chainId: supportedChainId, + env, + }) + if (entitlement <= 0n) return + + const decimals = CHAIN_DECIMALS[supportedChainId] ?? 18 + eligible.push({ + chainId: supportedChainId, + amount: formatUnits(entitlement, decimals), + }) + } catch { + // Keep per-chain reads best-effort: one RPC/SDK failure should not block the widget. + } + }), + ) + + if (!mountedRef.current) return + eligible.sort((a, b) => b.chainId - a.chainId) + setClaimablesByChain(eligible) + }, [env]) + + const loadDailyStats = useCallback(async (): Promise => { + let maxClaimers = 0 + let totalClaimed = 0 + + await Promise.all( + SUPPORTED_CHAINS.map(async (supportedChainId) => { + try { + const chain = CHAIN_CONFIGS[supportedChainId] + const rpcUrl = chain.rpcUrls.default.http[0] + if (!rpcUrl) return + const publicClient = createPublicClient({ chain, transport: http(rpcUrl) }) + const stats = await checkGenericDailyStats({ + publicClient, + chainId: supportedChainId, + env, + }) + const claimers = Number(stats.claimers) + if (claimers > maxClaimers) maxClaimers = claimers + const decimals = CHAIN_DECIMALS[supportedChainId] ?? 18 + totalClaimed += Number(formatUnits(stats.amount, decimals)) + } catch { + // Best effort aggregation. + } + }), + ) + + if (!mountedRef.current) return + setDailyStats({ + dailyNumberOfClaimers: maxClaimers, + dailyClaimedAmount: totalClaimed, + }) + }, [env]) + + // --------------------------------------------------------------------------- + // loadClaimStatus — primary refresh action. + // Calls getWalletClaimStatus() and maps the SDK result to widget status. + // --------------------------------------------------------------------------- + const loadClaimStatus = useCallback(async () => { + if (!isConnected || !address) { + await loadClaimablesByChain() + await loadDailyStats() + setStatus('not_connected') + return + } + + // Always refresh per-chain claimables for a connected wallet, even if the + // currently active chain is unsupported. This keeps the cross-chain + // breakdown visible while prompting for network switching. + await loadClaimablesByChain() + await loadDailyStats() + + if (!onSupportedChain) { + // Wallet connected but on an unsupported chain — surface switch_chain action + setStatus('not_connected') + return + } + + setStatus('loading') + setError(null) + + const clients = createClients() + if (!clients) { + setStatus('not_connected') + return + } + const sdk = createSdkInstances(clients) + if (!sdk) { + setStatus('not_connected') + return + } + + try { + const walletStatus = await sdk.claimSDK.getWalletClaimStatus() + if (!mountedRef.current) return + + if (walletStatus.status === 'not_whitelisted') { + // User needs face-verification before claiming + setStatus('not_whitelisted') + setAmount(null) + } else if (walletStatus.status === 'can_claim') { + // User is whitelisted and has unclaimed UBI + setStatus('eligible') + const decimals = CHAIN_DECIMALS[chainId as SupportedChains] ?? 18 + setAmount(formatUnits(walletStatus.entitlement, decimals)) + } else { + // User is whitelisted but has already claimed for this period + setStatus('already_claimed') + setNextClaimTime(walletStatus.nextClaimTime ?? null) + setAmount(null) + } + } catch (err: unknown) { + if (!mountedRef.current) return + setStatus('error') + setError(humanReadableError(err)) + } + }, [ + isConnected, + address, + onSupportedChain, + chainId, + createClients, + createSdkInstances, + loadClaimablesByChain, + loadDailyStats, + ]) + + // Auto-refresh claim status whenever wallet connection or chain changes + useEffect(() => { + void loadClaimStatus() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isConnected, address, chainId]) + + // --------------------------------------------------------------------------- + // handleClaim — executes the UBI claim transaction via ClaimSDK. + // Transitions: eligible → claiming → success | error + // --------------------------------------------------------------------------- + const claimOnChain = useCallback( + async (targetChainId: number): Promise => { + if (!provider) throw new Error('No wallet provider available') + if (!address) throw new Error('Wallet not connected') + + if (!isSupportedChain(targetChainId)) { + throw new Error(`Unsupported chain for citizen-sdk: ${targetChainId}`) + } + + setStatus('claiming') + setError(null) + + // Ensure the wallet is on the target chain before signing. + await ( + provider as { + request: (args: { method: string; params: unknown[] }) => Promise + } + ).request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: `0x${targetChainId.toString(16)}` }], + }) + + const sdk = createSdkInstancesForChain(targetChainId) + if (!sdk) throw new Error('Unable to initialize SDK clients for target chain') + + return sdk.claimSDK.claim() + }, + [provider, address, createSdkInstancesForChain], + ) + + const handleClaim = useCallback(async (): Promise => { + if (!chainId) throw new Error('No active chain selected') + + setStatus('claiming') + setError(null) + + try { + const receipt = await claimOnChain(chainId) + if (!mountedRef.current) return receipt + await loadClaimStatus() + return receipt + } catch (err: unknown) { + if (!mountedRef.current) throw err + setStatus('error') + setError(humanReadableError(err)) + throw err + } + }, [chainId, claimOnChain, loadClaimStatus]) + + // --------------------------------------------------------------------------- + // handleVerify — initiates the GoodID face-verification flow. + // Opens in a new tab; the page reloads/redirects back when complete. + // --------------------------------------------------------------------------- + const handleVerify = useCallback(async (): Promise => { + const clients = createClients() + const sdk = createSdkInstances(clients) + if (!sdk) throw new Error('Wallet not connected or unsupported chain') + + const fvLink = await sdk.identitySDK.generateFVLink( + false, + options.rdu ?? (typeof window !== 'undefined' ? window.location.href : undefined), + chainId ?? undefined, + ) + if (typeof window !== 'undefined') { + window.open(fvLink, '_blank', 'noopener,noreferrer') + } + }, [createClients, createSdkInstances, chainId, options.rdu]) + + const handleConnect = useCallback(async (): Promise => { + setStatus('connecting') + setError(null) + try { + await connect() + await loadClaimStatus() + } catch (err: unknown) { + if (!mountedRef.current) throw err + setStatus('not_connected') + throw err + } + }, [connect, loadClaimStatus]) + + // --------------------------------------------------------------------------- + // handleSwitchChain — requests the wallet to switch to a supported chain. + // Uses the EIP-3326 wallet_switchEthereumChain method. + // --------------------------------------------------------------------------- + const handleSwitchChain = useCallback( + async (targetChainId: number): Promise => { + if (!provider) throw new Error('No wallet provider available') + await ( + provider as { + request: (args: { method: string; params: unknown[] }) => Promise + } + ).request({ + method: 'wallet_switchEthereumChain', + params: [{ chainId: `0x${targetChainId.toString(16)}` }], + }) + }, + [provider], + ) + + // --------------------------------------------------------------------------- + // Derived state: primaryAction and primaryLabel + // --------------------------------------------------------------------------- + const primaryAction: CitizenClaimWidgetAdapterState['primaryAction'] = useMemo(() => { + if (status === 'connecting') return 'connect' + if (status === 'not_connected') { + // Connected but on wrong chain → switch_chain; not connected → connect + return isConnected && !onSupportedChain ? 'switch_chain' : 'connect' + } + if (status === 'not_whitelisted') return 'verify' + // Keep the claim button mounted while a claim is in-flight so UI copy can + // switch to "Claiming..." without hiding the action surface. + if (status === 'claiming') return 'claim' + if (status === 'eligible') return 'claim' + if (status === 'error') return 'refresh' + return 'none' + }, [status, isConnected, onSupportedChain]) + + const primaryLabel: string = useMemo(() => { + switch (primaryAction) { + case 'connect': + if (status === 'connecting') return 'Connecting...' + return 'Connect' + case 'verify': + return 'Verify Identity' + case 'claim': + return 'Claim' + case 'refresh': + return 'Retry' + case 'switch_chain': + return 'Switch Network' + default: + if (status === 'claiming') return 'Claiming...' + if (status === 'success') return 'Claimed!' + if (status === 'already_claimed') return 'Next Claim' + return '' + } + }, [primaryAction, status]) + + const state: CitizenClaimWidgetAdapterState = useMemo( + () => ({ + status, + address: address ?? null, + chainId: chainId ?? null, + amount, + token: 'G$', + primaryAction, + primaryLabel, + error, + nextClaimTime, + claimablesByChain, + dailyStats, + }), + [ + status, + address, + chainId, + amount, + primaryAction, + primaryLabel, + error, + nextClaimTime, + claimablesByChain, + dailyStats, + ], + ) + + const actions: CitizenClaimWidgetAdapterActions = useMemo( + () => ({ + connect: handleConnect, + refresh: loadClaimStatus, + startVerification: handleVerify, + claim: handleClaim, + claimOnChain, + switchChain: handleSwitchChain, + }), + [handleConnect, loadClaimStatus, handleVerify, handleClaim, claimOnChain, handleSwitchChain], + ) + + return { state, actions } +} diff --git a/packages/citizen-claim-widget/src/element.ts b/packages/citizen-claim-widget/src/element.ts new file mode 100644 index 0000000..13ee737 --- /dev/null +++ b/packages/citizen-claim-widget/src/element.ts @@ -0,0 +1,26 @@ +import { createMiniAppElement } from '@goodwidget/embed' +import { CitizenClaimWidget } from './CitizenClaimWidget' +import type React from 'react' + +/** + * A Custom Element class wrapping the CitizenClaimWidget React component. + * + * Register it with any tag name: + * customElements.define('gw-citizen-claim', CitizenClaimWidgetElement) + * + * Then use in HTML: + * + * + * Set the wallet provider and theme overrides via JS properties: + * const el = document.querySelector('gw-citizen-claim') + * el.provider = window.ethereum + * el.themeOverrides = { tokens: { color: { primary: '#00AFFE' } } } + */ +export const CitizenClaimWidgetElement = createMiniAppElement( + CitizenClaimWidget as React.ComponentType>, + { + shadow: true, + defaultTheme: 'light', + events: ['claim-success', 'claim-error'], + }, +) diff --git a/packages/citizen-claim-widget/src/index.ts b/packages/citizen-claim-widget/src/index.ts index 8e01c81..8c22928 100644 --- a/packages/citizen-claim-widget/src/index.ts +++ b/packages/citizen-claim-widget/src/index.ts @@ -1,5 +1,8 @@ +// Integration metadata (links this widget to the citizen-sdk capability manifest) export { citizenClaimIntegration } from './integration' export type { CitizenClaimIntegration } from './integration' + +// Adapter contract types export type { CitizenClaimWidgetAdapterActions, CitizenClaimWidgetAdapterResult, @@ -14,3 +17,10 @@ export type { CitizenClaimWidgetStatus, CitizenClaimWidgetSuccessDetail, } from './widgetRuntimeContract' + +// Adapter hook +export { useCitizenClaimAdapter } from './adapter' +export type { UseCitizenClaimAdapterOptions } from './adapter' + +// Widget component +export { CitizenClaimWidget } from './CitizenClaimWidget' diff --git a/packages/citizen-claim-widget/src/integration.ts b/packages/citizen-claim-widget/src/integration.ts index 61a3323..d2e8f12 100644 --- a/packages/citizen-claim-widget/src/integration.ts +++ b/packages/citizen-claim-widget/src/integration.ts @@ -6,12 +6,15 @@ export const citizenClaimIntegration = { 'whitelistStatus', 'claimStatus', 'claimEntitlement', + 'genericClaimEntitlement', + 'dailyStats', 'startVerification', 'claim', ], chains: [122, 42220, 50], states: [ 'loading', + 'connecting', 'not_connected', 'not_whitelisted', 'eligible', @@ -24,4 +27,3 @@ export const citizenClaimIntegration = { } as const export type CitizenClaimIntegration = typeof citizenClaimIntegration - diff --git a/packages/citizen-claim-widget/src/register.ts b/packages/citizen-claim-widget/src/register.ts new file mode 100644 index 0000000..38a7472 --- /dev/null +++ b/packages/citizen-claim-widget/src/register.ts @@ -0,0 +1,27 @@ +import { CitizenClaimWidgetElement } from './element' + +const DEFAULT_TAG_NAME = 'gw-citizen-claim' + +/** + * Register the custom element. + * + * Call once at the top of your app or in a