Skip to content

fix(dashboard): compute StatCard trends from sparkline history (#92) - #99

Open
annieolivia61-ux wants to merge 1 commit into
MergeFi:mainfrom
annieolivia61-ux:fix/issue-92-statcard-trends
Open

fix(dashboard): compute StatCard trends from sparkline history (#92)#99
annieolivia61-ux wants to merge 1 commit into
MergeFi:mainfrom
annieolivia61-ux:fix/issue-92-statcard-trends

Conversation

@annieolivia61-ux

Copy link
Copy Markdown

Closes #92

Removes the hardcoded trend literals (12 / 8 / 18) from the contributor and sponsor dashboards and computes the trend from the same history array already rendered as each card's sparkline.

What changed

  • New src/lib/trend.tscomputeTrend(history)
    Week-over-week percentage change: ((latest - prior) / prior) * 100, rounded to a whole number to match StatCard's N% vs last period display.

    • history fewer than 2 points or a zero prior period → returns undefined (the trend row is hidden, never a fabricated placeholder).
    • No 0undefined ambiguity: a genuine flat period returns 0.
  • src/app/dashboard/contributor/page.tsx

    • Lifetime earnings card: trend={fetchStatus === "loaded" ? computeTrend(contributorEarningsHistory) : undefined} (was 12).
    • Merged PRs card: trend={fetchStatus === "loaded" ? computeTrend(contributorSparkline) : undefined} (was 8).
  • src/app/dashboard/sponsor/page.tsx

    • Total paid out card: trend={fetchStatus === "loaded" ? computeTrend(sponsorSpendHistory) : undefined} (was 18).
  • Tests

    • src/lib/trend.test.ts — unit tests for up/down/flat/short/zero-prior/rounding cases.
    • src/components/ui/StatCard.test.tsx — negative and zero-trend rendering coverage (previously every caller passed a positive literal, so the down/rose path was never exercised).

Not changed (from the audit in the issue)

  • Landing page platformStats.* values are derived live from fetched stats — not hardcoded.
  • Maintainer dashboard StatCards use real derived values, not literals.
  • Reputation page uses real profile values.
  • The sponsor dashboard's dev-only kitchen-sink showcase card trend={5} is intentionally static sample data for the component gallery, matching its other hardcoded sample props — left as-is.

Pre-existing behavior acknowledged in the issue

StatCard renders a genuine 0 trend with the green up arrow because trendUp = typeof trend === "number" && trend >= 0. computeTrend can now legitimately return 0 for a flat week; the component's >= 0 arrow choice is pre-existing and out of scope for this fix (documented in trend.ts JSDoc and covered by a test).

Drive-by fix: duplicate validateTeamSplits in src/lib/utils.ts

src/lib/utils.ts contained two validateTeamSplits exports (introduced in commit 7c8260c2, "Fix #5"). The first only accepted number percentages and had no tolerance parameter; the second (kept) accepts string | number percentages with a tolerance param. The duplicate makes next build fail with "the name validateTeamSplits is defined multiple times", so CI's build step was already red on main. Removed the older, less-capable copy — no behavior change for existing callers.

Verification

  • npm test — 21 passed / 21 (2 suites).
  • npm run lint — clean.
  • npm run build — compiles, TypeScript check passes, all 13 routes generated.
  • Note: local next build on this machine needs NEXT_FONT_GOOGLE_MOCKED_RESPONSES because the sandbox has no network access to fonts.googleapis.com / fonts.gstatic.com (fonts are downloaded at build time). CI has network access and downloads the real Geist/Geist Mono fonts.

@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

@annieolivia61-ux is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

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

Labels

None yet

Projects

None yet

1 participant