Skip to content

feat(apps): AI Credits analytics data widget - #179

Draft
goodbounties-nanoclaw-agent[bot] wants to merge 21 commits into
mainfrom
feat/ai-credits-analytics-web
Draft

feat(apps): AI Credits analytics data widget#179
goodbounties-nanoclaw-agent[bot] wants to merge 21 commits into
mainfrom
feat/ai-credits-analytics-web

Conversation

@goodbounties-nanoclaw-agent

Copy link
Copy Markdown
Contributor

Implements #178 (plan sub-issue for #176 — AI Credits analytics data widget).

Summary

  • Adds a new standalone app apps/ai-credits-analytics-web (Vite + React + TamaguiProvider), following the apps/ai-credits-web / apps/superfluid-campaign-web scaffold pattern. No wallet connection anywhere.
  • Read-only AntSeed AI Credits analytics dashboard: 3 scorecards (G$ spent, AI credits used, G$ flow rate), 3 charts (G$ volume, AI credits used, unique wallets — all via existing @goodwidget/ui chart components: Scorecard, LineAreaChart, BarChart), and a paginated daily-summary table (DataTable + an app-local PaginatedDataTable wrapper, since DataTable has no built-in paging).
  • Data layer (src/lib/analyticsApi.ts, analyticsConversions.ts, generateDemoData.ts, src/hooks/useAnalyticsData.ts) is an internal module inside the app, not a separate package, per plan. Ported from GoodDollar/data-team's reference dashboard (projects/antseed-analytics/dashboard/app.js): live-fetch-with-demo-fallback state machine, manual Live/Demo toggle (stays clickable even when live is unavailable — shows an inline "not yet deployed" message instead of disabling), 5-minute auto-refresh, and a refresh button that POSTs then re-fetches.
  • All wei-denominated values stay as BigInt-safe strings end-to-end; conversions reduce precision in BigInt space before ever calling Number().
  • No new packages/ui components were needed — all 5 analytics chart components already cover this issue's requirements.

Out of scope (per Bounty Lead sign-off on the plan)

  • The existing ai-credits-web/superfluid-campaign-web deploy workflows' generic job/environment naming is not touched here — tracked as a separate follow-up.
  • This app's own deploy workflow (.github/workflows/deploy-ai-credits-analytics-web.yml) is drafted and committed locally but intentionally not included in this PR pending Laurence confirming the Vercel project/secret specifics for this app — will be pushed as a follow-up commit once confirmed.

Testing

  • pnpm turbo run build --filter=@goodwidget/ai-credits-analytics-web — passes.
  • pnpm turbo run lint --filter=@goodwidget/ai-credits-analytics-web — passes.
  • New Playwright spec apps/ai-credits-analytics-web/tests/dashboard.spec.ts (desktop/Chromium project) — 6/6 passing, covering: live data render, demo fallback, toggling to Live while unavailable (inline message, toggle stays clickable), refresh loading state, empty state, and table pagination.

Human-reviewer checklist

  • Confirm the existing-workflow job-naming fix is intentionally excluded from this PR (separate follow-up, per plan sign-off).
  • Confirm dropping the old dashboard's hardcoded antseed-integration PR [Plan] Build packages/savings-widget: SDK integration, UI mapping, and execution checklist #19 link from the "live unavailable" copy (replaced with generic "not yet deployed" text) is correct.
  • Confirm the app-local PaginatedDataTable wrapper (vs. promoting pagination into packages/ui's DataTable) is the right call for now.
  • Confirm dev port 3003 assignment for this app.
  • Review the held-back deploy-ai-credits-analytics-web.yml (committed locally, not in this PR) once Laurence confirms Vercel project/secret specifics, before it's pushed.

goodbounties-nanoclaw-agent Bot and others added 17 commits August 5, 2026 12:47
Adds a reusable Scorecard component to packages/ui — a single-metric KPI
card with label, formatted value, optional trend indicator, and bare/card
variants. Implements #139's compact/decimal/none formatting modes via a
shared formatMetricValue utility, and a golden-ratio modular typography
scale (base 24px, ratio 1.618, 12px floor) across sm/md/lg sizes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- formatMetricValue: fix a rounding-boundary bug where a scaled value could
  round up to the next unit's threshold without promoting (e.g. 999_950 ->
  "1000.0K" instead of "1.0M"); guard non-finite input (NaN/Infinity) with a
  "--" fallback shared by all consumers; note the intentional en-US locale.
- Scorecard: set both testID and data-testid so React Native test tooling
  and web DOM queries both work; mark the trend arrow SVG as decorative
  (accessible=false / aria-hidden) since adjacent text already conveys
  direction; give resolveThemeColor a visible fallback and dev warning
  instead of silently rendering an empty fill; type its theme param via
  ReturnType<typeof useTheme> instead of an unsafe double cast.
- package.json: move react-native-svg to peerDependencies (kept in
  devDependencies for local build/test) to avoid native-module duplication
  for consumers.
- Storybook story + smoke test: render all 5 mock-data rows in both the
  bare and card variants with per-row testIDs, and assert all 10 are
  visible so the test matches what it claims to cover.

Co-Authored-By: Claude <noreply@anthropic.com>
…ing pass

- formatMetricValue: whole numbers below the compact threshold render
  without decimals ("47", not "47.0").
- Scorecard card variant: vertically centers content regardless of
  whether a trend row is present.
- Value text uses $color instead of $primary; prefix/suffix render at
  fontWeight 400 in $placeholderColor, subordinate to the value.
- Card variant elevation now uses a lightness-overlay + top highlight
  instead of a hard border, scoped to Scorecard's <Card> call site so
  the shared Card primitive is untouched.
- Spacing (label-to-value gap, value-to-trend gap, card padding) now
  derives from the same golden-ratio constants as the type scale.
- Bump the Scorecard smoke test's viewport height to fit the taller
  card layout without clipping the screenshot.

Co-Authored-By: Claude <noreply@anthropic.com>
Second consumer (PieDonutChart, and the 3 charts after it) needs the same
theme-token-to-raw-color resolution Scorecard already does privately.
Extracted to packages/ui/src/utils/resolveThemeColor.ts rather than
duplicating a 5th time, mirroring how formatMetricValue was shared.
Scorecard.tsx is untouched — it already shipped under a prior issue and
migrating it is out of this task's scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Generalizes FundingDistributionChart's SVG arc technique into a themeable
packages/ui primitive: computed ring geometry supports innerRadius from 0
(filled pie) to a thin donut, sort/maxSlices "Other" aggregation, legend
with percentages, empty/stress states, and onSegmentPress.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Vertical/horizontal categorical bar chart with nice-number axis ticks,
zero-baseline-aware single-edge-rounded bars, graceful long-label
truncation, and sub-pixel-safe rendering for large category counts.
Follows Scorecard/PieDonutChart conventions (createComponent, theme
color resolution, golden-ratio type scale).

Also adds a Text primitive to the Storybook react-native-svg web shim
— needed because BarChart is the first chart to render labels inside
the SVG (for pixel-precise axis alignment) rather than via Tamagui
Text, and the shim never had to support that primitive before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Time-series line/area chart with linear/monotone/step interpolation,
optional area-fill gradient, reference lines, multi-series with an
optional secondary y-axis, null-gap handling (connectNulls), and
adaptive x-axis label thinning/truncation for dense datasets, mirroring
BarChart's established truncateLabelToWidth pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Shared CHART_FONT_FAMILY constant applied to every SVG <Text> in
  BarChart and LineAreaChart, matching the default preset's sans-serif
  typography stack instead of the browser's default serif fallback
  (react-native-svg's Text isn't part of Tamagui's styling system, same
  reason resolveThemeColor exists for fill/stroke).
- PieDonutChart's Default story now shows the spec default (innerRadius
  0.6, donut with center metric) instead of overriding it to a flat
  pie; the pie mode moves to its own PurePie story.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
centerContentMaxWidth was derived from ringRadius * (1 - innerRadius),
which shrinks as the hole grows instead of growing with it — ringRadius
is the stroke's centerline, not the hole radius. Compute the actual hole
radius (ringRadius - strokeWidth / 2) and size the available square off
that instead. Also default the center value's own formatting to 0
decimals (450K, not 450.0K) so typical aggregated totals fit the hole at
the component's default size.

Co-Authored-By: Claude <noreply@anthropic.com>
Pure-Tamagui data table with typed columns, sorting, striping, sticky
header, and horizontal/vertical scroll. Applies the design-hierarchy
rules from the Pie/Bar/Line fix round: muted $placeholderColor headers
(bold weight kept per spec's own rule 4) vs full-contrast $color data
values.

Co-Authored-By: Claude <noreply@anthropic.com>
formatMetricValue's compact formatter always applied toFixed(decimals) to
the scaled value, even when it landed on a whole unit (892000 -> "892.0K"
instead of "892K"). Mirrors the same whole-number check already used in the
below-threshold branch. Affects BarChart/LineAreaChart axis labels and
DataTable cells.

Also backfills missing Playwright screenshot coverage requested in QA:
Pie/Donut empty + stress, Bar empty, Line/Area step/multi-series/gap/empty/
single-point, DataTable empty/null-cells/card variant.

Co-Authored-By: Claude <noreply@anthropic.com>
…pped elements

Several new QA-round screenshots (Pie/Donut, Bar, Line/Area empty states,
Line/Area step/single-point, DataTable empty/nulls) used element-level
locator screenshots instead of the established screenshotStory() full-iframe
helper, producing tightly-cropped composites inconsistent with the rest of
the suite.

DataTable/Default now uses a taller viewport (1800px) so the card variant,
previously captured as a separate cropped shot, renders within the same
full-page capture as the bare table.

Co-Authored-By: Claude <noreply@anthropic.com>
examples/react-web's local web shim for react-native-svg never got the
Text/Defs/LinearGradient/Stop passthroughs that examples/storybook's copy
already has. BarChart and LineAreaChart import these directly from
react-native-svg, which resolves to this shim in the web build, so
example-react-web#build failed at "Text" is not exported by
reactNativeSvg.tsx — and since all 3 PR #148 Vercel preview checks share
this turbo build task, all 3 were failing on it.

Mirrors the existing storybook shim's implementation exactly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
examples/html/src/shims/reactNativeSvg.tsx had the identical gap already
fixed in examples/react-web (missing Text/Defs/LinearGradient/Stop),
which was the next failure turbo hit on the shared example-html#build
task once the react-web build was unblocked.

apps/superfluid-campaign-web and apps/ai-credits-web each keep their own
differently-structured shim (src/reactNativeSvgWeb.tsx, aliased directly
in vite.config.ts rather than living under a shims/ folder) with a wider
pre-existing gap: also missing G, needed since PieDonutChart. Added
G/Text/Defs/LinearGradient/Stop to both, following each file's own
per-element-typed function style rather than the shims/ copies'
createPassthroughSvgPrimitive factory.

Full `pnpm build` across the monorepo now succeeds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nt stories

Add an explicit-render Controllable story to each analytics component
(BarChart, PieDonutChart, LineAreaChart, DataTable, Scorecard), leaving
Default fixed/static with a comment noting Controls are inert there by
design, matching the Stepper/Card convention.

Root cause of the reported inertness: any argType-covered prop absent
from a story's args object renders as a non-functional "Set boolean/
string/number" placeholder button in Storybook's live Controls panel
instead of a working control, until clicked once to initialize a
default. Every argType-covered prop across all 5 components now has an
explicit default in Controllable's args, matched to each component's
own real internal default value, so every control renders live and
interactive on first load.

Co-Authored-By: Claude <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
New standalone read-only Vite/React app (@goodwidget/ai-credits-analytics-web)
visualizing AntSeed AI Credits activity: G$ volume, credit usage, and unique
wallet counts, sourced from the AntSeed Analytics Worker with a local demo
fallback. Ported from GoodDollar/data-team's reference dashboard, composed
entirely from existing @goodwidget/ui chart primitives (Scorecard,
LineAreaChart, BarChart, DataTable). No wallet connection.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
…s-web

Vercel token/project-id secret naming confirmed by Laurence; job/environment
naming scoped to this new workflow only per the same confirmation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
Copilot AI lite review requested due to automatic review settings August 21, 2026 14:13
@L03TJ3
L03TJ3 deployed to internal August 21, 2026 14:13 — with GitHub Actions Active
@L03TJ3
L03TJ3 deployed to internal August 21, 2026 14:13 — with GitHub Actions Active
@L03TJ3
L03TJ3 deployed to internal August 21, 2026 14:13 — with GitHub Actions Active
@goodbounties-nanoclaw-agent
goodbounties-nanoclaw-agent Bot force-pushed the feat/ai-credits-analytics-web branch from 11fd95f to 613fe8c Compare August 21, 2026 15:37
…o a reusable GoodData widget package

Moves connector/config, fetch/validate/normalize/refresh, and dashboard
composition logic out of apps/gooddata-analytics-web into
packages/gooddata-widget, with a dashboard registry (mirroring the
manifest.ts pattern) and connector registry so future dashboards can be
added without copy-pasting a new app. apps/gooddata-analytics-web is now a
thin host: mount/config + deploy entry point only, with an SPA rewrite so
direct navigation and refresh work on dashboard subpaths.

Adds Storybook QA fixtures for the widget's loading/live/demo/live-unavailable/
empty states and a Playwright spec with baseline screenshots, matching the
existing GoodWidget test convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

On-Behalf-Of: BountyCoder[onecli] (yaskkeryodtdijpv)
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.

2 participants