Skip to content

fix(frontend/dashboard): chart tooltip and axis-tick money formatting does not pin a locale #1733

Closed

Description

@cristim

frontend/src/dashboard.ts formats dollar values with 5-6 independent .toLocaleString() calls inside Chart.js tooltip and axis-tick callbacks, none of which pin a locale. This is the same defect #1728 fixed in formatCurrency, in a file that fix did not reach.

Exact line numbers are listed in PR #1732's body.

Why it was scoped out of #1732

Deliberately, and correctly. Those call sites render to canvas, not the DOM; no test exercises them; and none of #1728's eight failures originated there. Widening a one-line locale fix into untested chart-rendering code would have been scope growth into the least verifiable part of the frontend.

The question worth answering first

Should these call formatCurrency instead of formatting money ad hoc?

If they can, that is the better fix: the underlying defect is that money formatting exists in more than one place, which is exactly what allowed the locale divergence. Consolidating removes the class rather than pinning six more instances of it. formatCurrency already pins 'en-US' after #1732 and already hardcodes the $ prefix, so a caller gets both behaviours for free.

If they genuinely cannot — different precision for axis ticks, abbreviated forms like $1.2M, or non-currency numbers mixed in — then pin each explicitly and record why consolidation was rejected, so the next person does not re-litigate it.

Resolve that before writing any code. The answer determines whether this is a 1-line change or a 6-line change.

Verification

Same standard as #1732: run under at least two locales (LANG=en_US.UTF-8 and LANG=de_DE.UTF-8). Since no test covers these paths, a locale run alone proves nothing — render the dashboard and look at the chart under a non-US locale before and after. If that is impractical, say so plainly in the PR rather than implying coverage that does not exist.

Do not fabricate tests for chart rendering to make this look verified. An honest "mechanical change, untested path, here is the visual check" is worth more than a test written to satisfy a checklist.

Context

Found while fixing #1728.

Activity

  1. cristim commented on Aug 7, 2026

    @cristim
    MemberAuthor

    Closing as fixed in PR #1732 (commit ab2b845), which extended the #1728 fix to these sites.

    The DRY question this issue asked to resolve first came back clean: dashboard.ts already imports formatCurrency and already uses it at :306, :308, :488 and :600. The six inline $${x.toLocaleString()} sites were therefore pure duplication rather than a signature or precision mismatch — all six values are guaranteed-finite whole-dollar numbers with a literal $ prefix, which is exactly formatCurrency's default signature.

    So the better fix was available: replace all six with formatCurrency(x) rather than pin 'en-US' six more times. That removes the duplication that allowed the divergence in the first place, instead of making the divergence consistent.

    Sites consolidated: :965, :976-979 (savings-by-service tooltip), :997 and :1150 (Chart.js axis-tick callbacks), :1134 (cumulative-savings tooltip).

    No tests were added, deliberately and as recorded in the PR: these render to canvas, had no existing coverage, and the change is a mechanical substitution. Verified via tsc, eslint, and the full suite under both LANG=en_US.UTF-8 and LANG=de_DE.UTF-8 (2781 pass / 0 fail under each) rather than by fabricating chart-rendering tests to satisfy a checklist.

    This issue existed for about twenty minutes and its whole value was forcing the consolidate-or-pin question to be answered before any code was written. Worth noting the pattern: filing the sibling finding separately, with the open question stated, produced a better fix than either silently widening the original PR or silently dropping the finding would have.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions