Skip to content

[DRAFT][PLAN] AI Credits dashboard: display, labeling, and scale fixes #224

Description

@goodbounties-nanoclaw-agent

[DRAFT][PLAN] AI Credits dashboard: display, labeling, and scale fixes

Type: Task
Parent issue: #222

Plan for #222.

This plan covers the 6 acceptance criteria in #222: relabeling/format fixes to the
AI Credits dashboard's scorecards, table, and volume chart, plus a fetch-window
reduction — all feedback from Hadar Rottenberg (CEO) after the PR #179 production
deploy of gooddata.gooddollar.org.

Base branch: main @ current head — fresh PR, not a reopen of PR #179's branch (#179 is merged/closed).

Resolved (Thales, 2026-08-31): Fix 1 is relabel-only. "Total G$ Spent" → "Total Credits Bought in G$" with USD equivalent + subscription sub-line. "AI Credits Used" stays its own separate scorecard (different metric — credits consumed vs. credits purchased). The 3-scorecard layout itself is unchanged.

Reference files mapped

All 6 changes are scoped to one existing package, no new packages needed:

Existing @GoodDollar packages imported: @goodwidget/ui (Scorecard, LineAreaChart, BarChart, formatMetricValue, DataTableColumnDef) and @goodwidget/embed, both already wired via packages/gooddata-widget/package.json workspace deps — no new dependency needed.

New components — package placement assessment

  • Scorecard sub-line (fix: basics #2): Scorecard (packages/ui) currently renders label / value+prefix+suffix / optional trend row — no slot for a second descriptive line under the value. A "breakdown" caption (e.g. "out of X G$ in subscription (streaming)") is a generic KPI-card capability, not specific to AI Credits — add an optional subLabel?: string prop to Scorecard in packages/ui, rendered as a dim caption-sized line below the value row (reusing ScorecardTrendRow's spacing tier). This keeps the primitive reusable for the ~26 other Scorecard call sites rather than one-off wrapping it inside gooddata-widget.
  • flowRateToMonthly() ([BOUNTY] Migrate First-Wave UI Primitives To Tamagui-Native Wrappers #3): stays in packages/gooddata-widget/src/dashboards/aiCredits/analyticsConversions.ts, alongside flowRateToDaily — this file is already AI-Credits-specific unit-conversion logic, not a reusable primitive.
  • Streaming line visibility (Map GoodWalletV2 UI components to GoodWidget Tamagui primitives #4): no new component. LineAreaChart (packages/ui) already supports secondaryYAxis and AiCreditsDashboard.tsx already wires the "streamed" series to it. Demo fixture data (generateDemoData.ts) has realistic non-zero streamed values, so the dual-axis path itself isn't obviously broken — needs live-data verification (see below) before deciding between fixing the existing dual-axis config vs. the issue's stated fallback (split into two single-axis charts).
  • No new widget package, no new packages/ui chart type — everything is a targeted edit to existing files.

Required states, flows, and behaviors

  1. Total Credits scorecard: relabel "Total G$ Spent" → "Total Credits Bought in G$", keep computing its primary value from weiToGd(gdOneTimeDepositsWei) + weiToGd(gdStreamedWei) as today, and add a USD-equivalent shown via weiToUsd(data.global.aiCreditsUsedWei). The "AI Credits Used" scorecard stays a separate, unchanged card (relabel-only per Thales — the 3-scorecard layout does not change).
  2. Streaming/subscription sub-line: new subLabel on the first scorecard reading "out of X G$ in subscription (streaming)" where X = weiToGd(data.global.gdStreamedWei).
  3. Flow-rate scorecard: relabel "G$ Flow Rate" → "Total Monthly Subscriptions", drop the suffix="/day", switch the value to flowRateToMonthly(data.global.gdTotalFlowRateWeiPerSecond) (new helper: BigInt(weiPerSecStr) * 2629746n, then reuse weiToGd's BigInt-safe reduction — mirrors flowRateToDaily's structure with SECONDS_PER_MONTH = 2629746n in place of SECONDS_PER_DAY).
  4. G$ Volume chart streaming line: verify the existing secondaryYAxis dual-axis rendering against real (not just demo) data shape; if genuinely not visibly distinguishable (e.g. because live streamed amounts are much smaller than deposits even on their own axis), fall back to two single-axis LineAreaCharts — one for one-time deposits, one for streamed — per [Feature] AI Credits dashboard: display, labeling, and scale fixes #222's explicit fallback instruction.
  5. Daily table precision: TABLE_COLUMNS's aiCreditsUsd formatter: .toFixed(2).toFixed(3).
  6. Fetch window: ANALYTICS_DAYS_REQUESTED: 36530 in connector.ts.

All 5 existing dashboard states (loading, live, demo, live-unavailable, empty) must continue to render correctly with the new labels/values — no new state is introduced.

Execution plan

  1. Add SECONDS_PER_MONTH + flowRateToMonthly() to analyticsConversions.ts, following the existing flowRateToDaily pattern and its BigInt-safety comments.
  2. Add optional subLabel?: string to Scorecard (packages/ui), rendered below the value row.
  3. Update AiCreditsDashboard.tsx: scorecard labels/values/sub-line, flowRateToMonthly wiring, TABLE_COLUMNS formatter precision.
  4. Investigate the G$ Volume chart's dual-axis rendering with realistic live-shaped data (demo generator or a captured live payload); fix or fall back to split charts per the required-behavior above.
  5. Update connector.ts's ANALYTICS_DAYS_REQUESTED to 30.
  6. Update Storybook QA fixtures / mock data (generateDemoData.ts, mockState.ts, goodDataWidgetStories.tsx) only if the new sub-line/relabeled values need different fixture shaping to demonstrate correctly — otherwise reuse as-is.
  7. Extend tests/widgets/gooddata-widget/states.spec.ts with assertions for the new scorecard labels, sub-line, and (if changed) split-chart testIDs; regenerate and commit updated baseline screenshots under tests/widgets/gooddata-widget/test-results/ (standing repo convention — not optional).
  8. Run typecheck/lint/build scoped to packages/gooddata-widget and packages/ui, plus the Playwright spec, before opening the PR. Commit one fix at a time, code + visual (Storybook/Playwright screenshot) verify before advancing to the next — same process as the feat(apps): AI Credits analytics data widget #179 rounds.

Acceptance criteria

  • First scorecard reads "Total Credits Bought in G$" with USD equivalent shown, "AI Credits Used" scorecard unchanged and still separate
  • Subscription/streaming portion shown as a sub-line under the first scorecard, computed via weiToGd(data.global.gdStreamedWei)
  • Flow-rate scorecard relabeled "Total Monthly Subscriptions", computed via new flowRateToMonthly(), no "/day" suffix
  • Streaming line is visibly distinguishable on the G$ Volume chart (dual-axis fix verified against realistic data, or split into two charts per the fallback)
  • Daily table's "AI Credits (USD)" column shows 3 decimal places
  • Dashboard's live fetch defaults to a 30-day window (ANALYTICS_DAYS_REQUESTED = 30)
  • All 5 existing dashboard states (loading/live/demo/live-unavailable/empty) still render correctly
  • tests/widgets/gooddata-widget/states.spec.ts updated and passing, with refreshed baseline screenshots committed

Human-reviewer checklist

  • Confirm scorecard-1's implementation matches Thales's resolved spec (relabel-only; "AI Credits Used" stays a separate, unchanged card; 3-scorecard layout unchanged)
  • Visually verify the G$ Volume chart's streaming line is actually legible at typical production data magnitudes, not just in the demo/ramped fixture data
  • Confirm flowRateToMonthly()'s 2629746 seconds-per-month constant and BigInt arithmetic match the rest of analyticsConversions.ts's precision conventions (4-decimal OUTPUT_PRECISION_DECIMALS reduction)
  • Confirm the new Scorecard.subLabel prop doesn't regress any other existing Scorecard call site's layout (it's additive/optional, but check other pages using variant="card")
  • Confirm Playwright baseline screenshots were regenerated and committed, not left stale
  • Confirm no unrelated widget/package was touched — this issue is scoped entirely to gooddata-widget's aiCredits dashboard plus one small packages/ui Scorecard addition

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions