Show whole-number metrics as whole numbers

The dashboard tiles printed every value at one decimal: '121,0 mmHg',
'60,0 bpm', '9.240,0' steps. TrendCard takes the metric's precision, and
blood pressure, pulse, HRV, steps and mg/dL glucose pass zero. The
measurement list names count-shaped units the way the insights pages do
('13 Etagen', '12,5 Atemzüge/min') instead of the source's 'count'.
This commit is contained in:
Marc-André Bombeck committed 2026-10-08 16:21:12 +02:00
1 parent b80dc14142
commit 554f36aeab
6 files changed
+108 -7

No files matched your search

@@ -0,0 +1,52 @@
import { describe, it, expect } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { Activity } from "lucide-react";
import { TrendCard } from "../trend-card";
import { I18nProvider } from "@/lib/i18n/context";
/**
* A whole-number metric reads as a whole number on the tile: "121 mmHg",
* not "121,0 mmHg", and "9.240" steps rather than "9.240,0".
*/
function render(node: React.ReactNode) {
return renderToStaticMarkup(
<I18nProvider initialLocale="de">{node}</I18nProvider>,
);
}
const base = {
label: "Schritte",
latest: 9240,
unit: "",
avg7: 9535.14,
avg30: 9100,
slope30: null,
icon: Activity,
};
describe("<TrendCard> fractionDigits", () => {
it("keeps one decimal by default", () => {
const html = render(<TrendCard {...base} />);
expect(html).toContain("9.240,0");
});
it("prints whole numbers, averages and deltas at 0", () => {
const html = render(
<TrendCard {...base} fractionDigits={0} trend7Delta={-1383.2} />,
);
expect(html).toContain("9.240");
expect(html).not.toContain("9.240,0");
expect(html).toContain("9.535");
expect(html).not.toContain("9.535,1");
expect(html).toContain("−1.383");
expect(html).not.toContain("−1.383,2");
});
it("reads a sub-step delta as zero at 0 decimals", () => {
const html = render(
<TrendCard {...base} fractionDigits={0} trend7Delta={0.3} />,
);
expect(html).toContain("±0");
});
});
+12 -3
View File
@@ -101,6 +101,13 @@ interface TrendCardProps {
* before (no reserved space, no layout shift).
*/
valueAdornment?: React.ReactNode;
/**
* Decimal places for the headline, the averages and the deltas. Defaults
* to 1. A whole-number metric (steps, mmHg, bpm, mg/dL) passes 0 so the
* tile reads "121 mmHg", not "121,0 mmHg" — the precision its own
* insights page uses.
*/
fractionDigits?: number;
}
export function TrendCard({
@@ -123,6 +130,7 @@ export function TrendCard({
staleDays = null,
emptyHint = null,
valueAdornment = null,
fractionDigits = 1,
}: TrendCardProps) {
const { t, tCount } = useTranslations();
const fmt = useFormatters();
@@ -152,7 +160,7 @@ export function TrendCard({
const arrowSentiment = getTrendSentiment(primarySignal, directionSentiment);
const trendColor = sentimentColorClass(arrowSentiment);
const formatValue = (value: number) => fmt.number(value, 1);
const formatValue = (value: number) => fmt.number(value, fractionDigits);
// v1.4.15 Fix 4 — the 7-day delta now shares the arrow's colour so
// both elements communicate the same sentiment for the same signal.
@@ -171,9 +179,10 @@ export function TrendCard({
const comparisonDeltaColor = sentimentColorClass(comparisonSentiment);
const formatDelta = (value: number): string => {
if (Math.abs(value) < 0.05) return `±0`;
// Below half a step of the shown precision the delta prints as zero.
if (Math.abs(value) < 0.5 * 10 ** -fractionDigits) return `±0`;
const sign = value > 0 ? "+" : "−";
return `${sign}${fmt.number(Math.abs(value), 1)}`;
return `${sign}${fmt.number(Math.abs(value), fractionDigits)}`;
};
// The label flips from "7d" / "7T" (mean) to "7d trend" / "7T-Trend"