Skip to content

fix(streaming-widget): finalize bounty coverage and evidence#38

Open
edehvictor wants to merge 3 commits into
GoodDollar:copilot/create-streaming-widgetfrom
edehvictor:fix/finalize-streaming-widget-36
Open

fix(streaming-widget): finalize bounty coverage and evidence#38
edehvictor wants to merge 3 commits into
GoodDollar:copilot/create-streaming-widgetfrom
edehvictor:fix/finalize-streaming-widget-36

Conversation

@edehvictor
Copy link
Copy Markdown
Collaborator

Refs #26
Refs #28
Refs #36
Builds on AI PR #31.

Summary

Finalizes the streaming widget bounty work on top of the existing AI PR branch by filling the missing runtime states, deterministic Storybook coverage, Playwright coverage, and screenshot evidence needed for human review.

Changes

  • Kept the widget shell on WidgetTabs for Streams, Pools, and Balances.
  • Added deterministic StreamingWidgetPreview wiring for Storybook and Playwright while preserving the live StreamingWidget adapter path.
  • Added stream history state to the runtime contract, adapter, and UI, including loading, empty, error, populated, and Show more states.
  • Added live GDA pool claim support by reading getClaimableNow from pool contracts and submitting claimAll, with separate pending/success/error state.
  • Strengthened create/update stream UI for invalid input, disconnected wallet, wrong chain, pending, success, and failure states.
  • Preserved injected wallet and custodial fixture stories, and added deterministic stories for loading, empty, error, create/update, pool claim, Base SUP balance/reserve, and non-Base reserve-disabled states.
  • Replaced the streaming-widget Playwright smoke tests with deterministic coverage for tab navigation, stream filters/history, create/update success/failure, pool claim state, reserve visibility by chain, and mobile/desktop layout evidence.
  • Added current screenshot evidence under tests/widgets/streaming-widget/test-results/.
  • Fixed small pre-existing lint blockers outside the widget package so the required full pnpm lint command passes.

Verification

  • pnpm install: Passed
  • pnpm build: Passed
  • pnpm lint: Passed with existing repo warnings only
  • pnpm test:demo tests/widgets/streaming-widget: Passed, 13/13 tests
  • git diff --check HEAD~2..HEAD: Passed, no whitespace errors

Evidence

Playwright screenshots are committed in tests/widgets/streaming-widget/test-results/ and cover:

  • disconnected wallet
  • tab navigation
  • wrong chain
  • loading, empty, error, and populated stream/history states
  • create/update invalid, pending, success, and failure states
  • pool claim idle, pending, success, and error states
  • Base SUP reserve and non-Base reserve-disabled states
  • mobile and desktop populated layouts

Notes

This PR intentionally targets copilot/create-streaming-widget so AI PR #31 can be updated before maintainer review.

@edehvictor
Copy link
Copy Markdown
Collaborator Author

Hi @L03TJ3, PR #38 is ready for review.

I followed the assigned bounty flow, built on top of the existing AI branch, posted the handoff on #36, and included verification/evidence.

Verified:

  • pnpm install
  • pnpm build
  • pnpm lint
  • pnpm test:demo tests/widgets/streaming-widget passing, 13/13

Thanks again for assigning this.

@L03TJ3 L03TJ3 linked an issue May 22, 2026 that may be closed by this pull request
12 tasks
@L03TJ3 L03TJ3 removed this from GoodBounties May 22, 2026
@L03TJ3 L03TJ3 requested review from a team, L03TJ3 and pheobeayo and removed request for a team and L03TJ3 May 22, 2026 12:23
setStreams(result.map((s) => toStreamListItem(s, address as Address)))
const normalizedStreams = result.map((s) => toStreamListItem(s, address as Address))
setStreams(normalizedStreams)
setStreamHistory(normalizedStreams)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice work wiring up the history state machine; the loading/empty/error/populated states all render correctly. One thing worth flagging for a follow-up: setStreamHistory here is receiving the same result as setStreams, because getActiveStreams only returns currently active (non-zero flowRate) streams. Terminated streams would need a separate subgraph query, something like a getPastStreams or getStreamHistory call, to populate a true history list. As it stands, the history section in the UI is showing the same data as the active streams list, and the "Show more" pagination is working against that same pool. Not blocking for this bounty since the UI states are all covered, but worth picking up as a follow-up so the history tab reflects actual past streams.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, agreed. I kept this as a follow-up because the current SDK path only exposes active streams here, and added a fixture note so the Storybook history data is easy to split once a dedicated past-stream query exists.

connect,
switchChain,
refreshStreams: fetchStreams,
refreshStreamHistory: fetchStreams,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Small note to go alongside the history comment above, refreshStreamHistory is pointing to fetchStreams here, so both refresh actions hit the same underlying call. When a dedicated history fetch is added, this line will need to point to the new callback. Easy to update then

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Agreed. Leaving refreshStreamHistory pointed at the current SDK-backed fetch for now; when a dedicated history callback lands this should switch to that separate fetch.

Comment on lines +325 to +338
const poolsWithClaimable = await Promise.all(
normalizedPools.map(async (pool) => {
try {
const [claimableAmount] = await viemClients.publicClient.readContract({
address: pool.poolId,
abi: GDA_POOL_CLAIM_ABI,
functionName: 'getClaimableNow',
args: [address as Address],
})

return {
...pool,
claimableAmount: claimableAmount > 0n ? claimableAmount : 0n,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The getClaimableNow read looks good, and the claimableAmount > 0n guard correctly handles the signed int256 return. One thing to watch: if this readContract call throws (RPC timeout, contract revert, etc.), the catch silently returns the pool with claimableAmount still at 0n from the toPoolMembershipItem fallback. In the UI, that makes the Claim button appear disabled with no explanation. A user with a real claimable balance would just see a greyed-out button and have no way to tell whether it's a data error or genuinely nothing to claim. Could we add a claimableAmountError flag to PoolMembershipItem and surface a small "Could not load claimable amount, tap to retry" note in PoolCard when the read fails?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 3494404: PoolMembershipItem now carries claimableAmountError, successful reads clear it, and failed getClaimableNow reads set it instead of silently falling back to an unexplained 0n state.

!state.streamHistoryError &&
recentStreams.length === 0 && (
<EmptyStateCard>
<Text secondary center>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is the UI side of the silent-failure issue flagged in the adapter's getClaimableNow catch block. When that read fails, claimableAmount stays at 0n, so canClaim is false and the button renders disabled with no explanation. Pairing this with the adapter fix, surfacing a claimableAmountError on the pool item, would let us show something like "Could not load claimable amount" here instead of just a greyed-out button.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in 3494404: PoolCard now surfaces the claimable amount load failure with a small inline “Could not load claimable amount. Tap to retry” note wired to refreshPools, while keeping Claim disabled until the amount is known.

// Story shell — renders the widget inside a fixed-width container that mirrors
// the GoodWalletV2 sidebar / bottom-sheet form factor.
// ---------------------------------------------------------------------------
const DEMO_ADDRESS = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is DEMO_ADDRESS intentionally Vitalik's well-known address? That's fine as a fixture, just worth confirming it's deliberate and that this address doesn't have any unexpected behaviour on Celo or Base in the test environment. If it's just a placeholder, a clearly synthetic address like 0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef might be less likely to confuse future contributors.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. Replaced the well-known address with a clearly synthetic fixture address in 3494404 to avoid confusing future contributors.

},
]

const sampleStreamHistory: StreamListItem[] = [
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sampleStreamHistory spreads sampleStreams at the top, which is consistent with the current adapter behaviour (both lists come from the same getActiveStreams call). When the adapter is updated to fetch real history separately, this fixture will need updating too. In a proper history model, the two lists should be disjoint, since active streams are ongoing and past streams are terminated. Could we add a comment here noting that the fixture should diverge once the adapter is corrected? Makes the follow-up easier to find.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Added the fixture comment in 3494404, noting that sampleStreamHistory mirrors the current SDK-backed adapter and should diverge once past-stream history is fetched separately.

Copy link
Copy Markdown

@pheobeayo pheobeayo left a comment

Choose a reason for hiding this comment

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

Impressive work so far @edehvictor , Kindly check through the comments and fix!

@edehvictor edehvictor requested a review from pheobeayo May 25, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GoodBounty] Finalize Streaming Widget PR

3 participants