mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 06:40:50 +00:00
fix(workouts): order the list newest-first; show the year on past-year dates
The canonical picker re-sorts its output to startedAt ASC for its rollup callers, so the list route sliced the oldest page and recent workouts never surfaced on a long history — re-establish newest-first after the pick. And a workout from a previous year now shows its year so it is not read as this year's.
This commit is contained in:
1 parent
546c5c7d8f
commit
05f80ad378
7 files changed
+48
-3
No files matched your search
@@ -147,6 +147,28 @@ describe("GET /api/workouts — canonical dedup", () => {
|
||||
expect(body.data.meta.droppedDuplicates).toBe(1);
|
||||
});
|
||||
|
||||
it("returns the most recent workouts first", async () => {
|
||||
// The canonical picker re-sorts its output to startedAt ASC (its rollup
|
||||
// contract), so the list route must re-establish newest-first AFTER the
|
||||
// pick — otherwise offset/limit slice the OLDEST page and recent workouts
|
||||
// never surface. These two never cluster (different day + slot).
|
||||
const older = makeRow("w-old", "APPLE_HEALTH", "2026-01-01T07:00:00Z");
|
||||
const newer = makeRow("w-new", "APPLE_HEALTH", "2026-07-01T07:00:00Z");
|
||||
vi.mocked(prisma.workout.findMany).mockResolvedValueOnce([
|
||||
newer,
|
||||
older,
|
||||
] as never);
|
||||
|
||||
const res = await GET(makeRequest());
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(body.data.workouts.map((w: { id: string }) => w.id)).toEqual([
|
||||
"w-new",
|
||||
"w-old",
|
||||
]);
|
||||
});
|
||||
|
||||
it("returns 401 without a session", async () => {
|
||||
vi.mocked(getSession).mockResolvedValueOnce(null);
|
||||
const res = await GET(makeRequest());
|
||||
|
||||
@@ -143,6 +143,17 @@ async function buildWorkoutsResponse(
|
||||
userRow?.sourcePriorityJson ?? null,
|
||||
);
|
||||
|
||||
// `pickCanonicalWorkoutRows` re-sorts its output to `startedAt ASC` (its
|
||||
// documented contract for the rollup callers). This surface is a
|
||||
// most-recent-first list, so the DB `orderBy startedAt desc` must be
|
||||
// re-established AFTER the pick — otherwise `offset`/`limit` slice the
|
||||
// OLDEST page and a user with a long history never sees recent workouts.
|
||||
canonical.sort((a, b) => {
|
||||
const delta = (b.startedAt?.getTime() ?? 0) - (a.startedAt?.getTime() ?? 0);
|
||||
if (delta !== 0) return delta;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
|
||||
const page = canonical.slice(offset, offset + limit).map((row) => ({
|
||||
id: row.id,
|
||||
sportType: row.sportType,
|
||||
|
||||
@@ -87,10 +87,14 @@ function formatDate(
|
||||
timeFormat: TimeFormatPreference,
|
||||
): string {
|
||||
const d = new Date(iso);
|
||||
// Show the year whenever the workout is not from the current year, so a
|
||||
// "Do., 16. Dez." from a previous year is never mistaken for this year's.
|
||||
const showYear = d.getFullYear() !== new Date().getFullYear();
|
||||
return getDateTimeFormat(locale, {
|
||||
weekday: "short",
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
...(showYear ? { year: "numeric" as const } : {}),
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
...hourCycleOptions(timeFormat),
|
||||
|
||||
Reference in new issue
Block a user