activity-stats: shared StatRow + canonical metrics across surfaces
Implements the activity-stats change (specs/activity-stats): - gpx: `movingTime(tracks)` — moving seconds from trackpoint timestamps, excluding stationary spans + long gaps; null when no timestamps. - stats.ts: pure formatters (distance/elevation/duration/speed/pace), sport-aware `deriveRate` (pace for foot sports, speed otherwise, speed default), and `activityStatItems` encoding the canonical order (distance · time · [moving] · pace/speed · ascent · descent; compact subset). - StatRow: one shared presentational component (size sm/lg), adopted on the activity detail (full set; loader derives moving time), route detail (distance/ascent/descent), feed card + profile list (compact). - i18n: journal.stats.* in en + de. Tests: movingTime (stationary/gap exclusion, moving ≤ elapsed), deriveRate, formatters, activityStatItems ordering + compact, StatRow render (jsdom). typecheck + lint + unit (gpx 63, journal 311) green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ede263d4d1
commit
0325d01bca
15 changed files with 482 additions and 67 deletions
29
apps/journal/app/components/StatRow.test.tsx
Normal file
29
apps/journal/app/components/StatRow.test.tsx
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// @vitest-environment jsdom
|
||||
import { describe, it, expect, afterEach } from "vitest";
|
||||
import { render, cleanup } from "@testing-library/react";
|
||||
import { StatRow } from "./StatRow.tsx";
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe("StatRow", () => {
|
||||
it("renders nothing for an empty item list", () => {
|
||||
const { container } = render(<StatRow items={[]} />);
|
||||
expect(container.firstChild).toBeNull();
|
||||
});
|
||||
|
||||
it("renders each item's value and label, in order", () => {
|
||||
const { container } = render(
|
||||
<StatRow
|
||||
items={[
|
||||
{ label: "Distance", value: "30.0 km" },
|
||||
{ label: "Time", value: "1h 0m" },
|
||||
{ label: "Avg speed", value: "30.0 km/h" },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
const labels = [...container.querySelectorAll("dt")].map((el) => el.textContent);
|
||||
const values = [...container.querySelectorAll("dd")].map((el) => el.textContent);
|
||||
expect(labels).toEqual(["Distance", "Time", "Avg speed"]);
|
||||
expect(values).toEqual(["30.0 km", "1h 0m", "30.0 km/h"]);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue