Skip to content

feat(statcard): redesign StatCard for explicit loading/error/zero/loa… - #67

Merged
chonilius merged 2 commits into
MergeFi:mainfrom
legend4tech:feat/statcard-edge-cases
Jul 20, 2026
Merged

feat(statcard): redesign StatCard for explicit loading/error/zero/loa…#67
chonilius merged 2 commits into
MergeFi:mainfrom
legend4tech:feat/statcard-edge-cases

Conversation

@legend4tech

Copy link
Copy Markdown
Contributor

Hardening StatCard Financial Reporting

closes #53

Summary

Refactored the StatCard component to handle financial figures robustly, resolving ambiguities around data loading, errors, zero-balances, and large-number overflows. Added explicit state management and updated all three dashboard call sites to prevent trust-eroding UI states (such as briefly flashing $0 budget remaining during initial data fetches).

Changes

1. StatCard Interface & Explicit States (src/components/ui/StatCard.tsx)

  • Introduced an explicit status prop ("loading" | "error" | "loaded") to break the dependency on inferring state from a bare number.
  • Loading State: Displays an animated shimmer skeleton that never renders a misleading 0 during network fetches.
  • Error State: Renders an em-dash with an "Error loading data" sub-label and an aria-label for screen reader accessibility on fetch failures.
  • Zero State: Implemented a distinct visual treatment for a genuine 0 value, complete with an explicit sub-label (customizable via zeroLabel, defaulting to "No activity yet") rather than conflating zero with null/error.

2. Domain-Appropriate Large-Number Policy

  • No Lossy Abbreviation: Financial figures are no longer abbreviated (e.g., no $1.2M) to preserve exact precision for sponsors and contributors.
  • Responsive Font Sizing: Introduced valueFontClass to dynamically scale font size (text-2xl down to text-base) based on character count, preventing layout overflow without truncating.
  • Accessible Tooltips: Applied the full unabbreviated figure to the title attribute so the exact value is always accessible via hover or keyboard focus.

3. Dashboard Integration

  • Updated SponsorDashboardPage, ContributorDashboardPage, and MaintainerDashboardPage to explicitly pass their respective data-fetching states to the new status prop.
  • Dashboard API catch blocks now set the UI state to "error" instead of defaulting data models to 0, ensuring that network failures aren't interpreted as sudden financial zeros.
  • Added a "dev-only" visual kitchen sink to sponsor/page.tsx that renders all four StatCard states side-by-side to prevent future styling regressions.

4. Comprehensive Testing (src/components/ui/StatCard.test.tsx)

  • Added a full test suite targeting the acceptance criteria.
  • Verified skeleton rendering in loading state (hiding actual values).
  • Verified error state accessibility and UI.
  • Verified visual distinctness of the zero state while ensuring string-zeros (e.g., "0%") safely bypass zero-treatment.
  • Verified that long numeric inputs trigger responsive font-scaling and tooltip injection, without layout truncation.

Acceptance Criteria Met

  • Loading, zero, error, and populated states are visually and semantically distinct.
  • Very large financial figures never overflow or truncate silently without an accessible exact-value affordance.
  • Dashboards no longer flash a 0 or blank stat card during pending Suspense boundaries or active data loading.

…ded states

- Add status prop ('loading' | 'error' | 'loaded', default 'loaded') so the
  three states are always visually and semantically distinct from each other
  and from a genuine zero value — eliminating the zero-flash trust problem.

- Loading state: animate-pulse skeleton shimmer, zero numbers ever shown.
- Error state: em-dash + 'Error loading data' sub-label in rose, AlertCircle
  icon, aria-label on wrapper for screen readers.
- Zero state (numeric 0): deliberate '0 USDC'/'0' with a configurable
  zeroLabel sub-text (e.g. 'No earnings yet') so a real zero is never
  ambiguous with a skeleton or an error.
- Loaded state: formatted value with responsive font-size scaling (text-2xl
  → text-xl → text-lg → text-base by string length) + title tooltip that
  always exposes the full unabbreviated exact figure. No '1.2M'-style
  abbreviation for financial figures.

- Add format prop ('currency' | 'count' | 'percent' | 'raw') so call sites
  pass numeric values and StatCard formats internally, enabling font scaling
  and large-number detection.

Update all three dashboard call sites:
- sponsor/page.tsx: add fetchStatus state (init 'loading'), remove page-level
  loading guard so page chrome is always visible, catch sets status='error'
  and data=null instead of falling back silently to zeros.
- contributor/page.tsx: same fetchStatus pattern; fix critical bug where catch
  block set lifetimeEarnings/mergedPRs/completionRate to 0 — a network error
  was visually identical to a brand-new account. Now sets stats=null +
  status='error'. Harden active-claims value guard to stats !== null.
- maintainer/page.tsx: wrap fetchBounties in try/catch; pass statStatus='error'
  to all four StatCards if fetch throws.

Add dev-only kitchen sink in sponsor dashboard showing all four states
side by side for continuous visual regression during development.

Add Jest + React Testing Library infrastructure (was entirely absent):
- jest.config.ts, jest.setup.ts, npm scripts 'test' and 'test:watch'
- StatCard.test.tsx: 11 RTL tests covering loading, error (x2), zero (x2),
  zero-as-string pass-through, typical loaded (x2), large-number font class +
  title tooltip, pre-formatted string pass-through. All 11 pass.

Lint: 0 errors. Build: clean (13/13 pages).
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

@legend4tech is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

@chonilius
chonilius merged commit 9c8f4b3 into MergeFi:main Jul 20, 2026
1 of 2 checks passed
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.

Redesign StatCard to distinguish loading, zero, error, and large-value states

2 participants