Repository navigation
Description
Feature summary
Add a reusable "Next Task" component to GoodWidget that restores the post-UBI-claim
feedback loop lost when goodwallet was rebuilt (never existed in gooddapp either):
after a user completes an action (initially claim), show a modal/bottom-sheet with a
single, dynamically-managed CTA (title, copy, image sourced externally) pointing the
user at a next task — voting, a community highlight, etc.
Problem or opportunity
The old goodwallet showed a feedback-loop modal after claiming UBI, nudging users
toward a next action (protocol/community highlight). That flow didn't carry over to
the new goodwallet and was never built in gooddapp. We want it back, but built as a
reusable primitive from the start — attachable to any widget's user action, not
hardcoded to claim — with easy, dynamic management of which CTA shows, and analytics
to measure whether it works.
Proposed solution
- Component: a
NextTaskModal/NextTaskCardcomposition inpackages/ui,
built from existing primitives (Drawer/Dialog,Card/GlowCard,Button) —
no existing CTA-card component to extend, this is new (same pattern as [Feature]: Add Data Table component #146 Data
Table / [Feature] Scorecard: add subtitle prop #223 Scorecard: composition of existing primitives, full prop contract
documented in the Plan sub-issue). - Trigger: a shared hook (e.g.
useNextTaskTrigger, home TBD — likely
packages/core) any widget calls after a user action succeeds. Today the only
precedent is narrow, single-widget callbacks onCitizenClaimWidget
(onClaimSuccess/onClaimError) — this generalizes that pattern instead of adding
another one-off callback. - Content fetch: CTA title/copy/image come from an external, dynamically-updatable
source; everything else (badge text, headline, dismiss copy) stays as in-app
defaults per the design reference. Open decision: what that external source is.
GoodWidget itself has no existing remote-config/CMS mechanism — confirmed absent.
Need Laurence to confirm whether there's existing GoodDollar-level infra to reuse
before we pick something net-new (constraint from Oliseh: prefer free/simple,
supports dynamic updates). - Navigation: if the CTA's target maps to a widget already available in the
same app/page, load it in-app; otherwise fall back to an external link, on both
web and native. GoodWidget has no shared cross-widget navigation abstraction
today, so "in-app" likely means the host app passes acanHandle/navigateTo
callback into the component. For native,Linking.openURLis already used
elsewhere (packages/governance-widget/src/hooks/useGovernanceMembership.ts) and
can be reused directly for the external-link fallback. - Analytics: no existing tracking convention anywhere in GoodWidget — confirmed
absent repo-wide. Proposing the component emit simple lifecycle events (shown,
CTA clicked, dismissed) via callback props, so the host app wires them to whatever
GoodDollar already uses at the org level. Open decision: pending Laurence —
does that org-level tool exist, or is this greenfield too? - Open scope question: PR Citizen-claim-widget: contract-sourced how-it-works copy (invite rewards) #191 flagged "native-app redirect handling for the
claim widget" as a separate, still-open research item. Need Laurence to confirm
whether that overlaps with this bounty's native external-link fallback, or is
unrelated and should stay out of scope.
Required states, flows, and behaviors
- Trigger fires after a watched action succeeds (e.g. claim) → fetch external CTA content.
- Fetch succeeds → show modal: status indicator (host-provided, e.g. "Claim completed"),
default headline/supporting copy, CTA card (badge, image, title, description from the
external source, primary button), dismiss ("Skip for now"). - Fetch fails or returns no CTA → modal does not show (no broken/empty state) — flagged
as an assumption, to confirm with the Bounty Lead. - Primary CTA tap, target widget available in-app → navigate to it in-app, no full reload.
- Primary CTA tap, no matching in-app widget → open external link (new tab on web,
Linking.openURLon native). - Dismiss/close (X) → closes modal, no navigation, fires a dismiss tracking event.
- Same trigger/component reusable after any widget's user action, not hardcoded to claim.
Acceptance criteria
- Reusable Next Task component built once in
packages/ui, not duplicated per widget. - CTA content (title, copy, image) sourced from an externally-managed, dynamically
updatable source (mechanism per the architecture decision above). - Trigger mechanism works from more than one widget (claim is the first consumer, not
the only one). - In-app navigation works when the CTA target widget is present on the same page.
- External-link fallback works on both web and native when no in-app target exists.
- Dismiss action closes the modal with no side effects.
- Shown / clicked / dismissed events are emitted for analytics wiring.
- Claim flow is wired as the first live consumer, restoring the original feedback loop.
- No broken/empty UI when CTA content is unavailable.
Additional context
Bounty Lead: Oliseh Genesis (GitHub: olisehgenesis), approved by Laurence. Notion spec:
"Goodbounties: Next task in the widget" (GoodDollar DX workspace). Design reference:
post-claim bottom-sheet mock (badge → headline → externally-sourced CTA card → dismiss).
Open items pending Laurence before this can be fully finalized:
- External CTA-content storage/management mechanism (needs to be free/simple, dynamic).
- Whether an org-level analytics/tracking tool already exists to wire the emitted events into.
- Whether PR Citizen-claim-widget: contract-sourced how-it-works copy (invite rewards) #191's native-redirect research item overlaps with this bounty's scope.
Create the plan
Based on the above description create an execution plan in a new sub-issue and preserve the original issue content unchanged.
Do not execute the plan until given instructions to do so.
Sub-issue requirements:
- Title format:
[DRAFT][PLAN] <what issue is being planned> - Type:
Task - Description must start with:
<sub-issue title> - Link the sub-issue back to this parent issue.
Instructions when creating the plan:
- 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
Plan specification required sections:
- Required states, flows, and behaviors
- Execution plan
- acceptance criteria
- human-reviewer checklist
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIn Progress
Activity
feat(ui,citizen-claim-widget): finalize next task component and claim…