From 7ed827f82cbed470926fed8f48cba8b96cdaf804 Mon Sep 17 00:00:00 2001 From: Petru Paler Date: Thu, 15 Jan 2026 12:47:12 +0000 Subject: [PATCH] Fix body battery showing zeros on dashboard after Garmin sync PocketBase coerces null number fields to 0 when reading. When Garmin API returned no data (null), we stored null, which became 0 on retrieval. The nullish coalescing (?? 100) in the API route didn't catch this because 0 is not nullish. Now store default value 100 when Garmin returns null, matching the existing pattern used for decision engine calculations. Co-Authored-By: Claude Opus 4.5 --- src/app/api/cron/garmin-sync/route.test.ts | 10 +++++++--- src/app/api/cron/garmin-sync/route.ts | 7 +++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/api/cron/garmin-sync/route.test.ts b/src/app/api/cron/garmin-sync/route.test.ts index d8fbd35..c6838dc 100644 --- a/src/app/api/cron/garmin-sync/route.test.ts +++ b/src/app/api/cron/garmin-sync/route.test.ts @@ -457,7 +457,11 @@ describe("POST /api/cron/garmin-sync", () => { expect(body.errors).toBe(1); }); - it("handles body battery null values", async () => { + it("stores default value 100 when body battery is null from Garmin", async () => { + // When Garmin API returns null for body battery values (no data available), + // we store the default value 100 instead of null. + // This prevents PocketBase's number field null-to-0 coercion from causing + // the dashboard to display 0 instead of a meaningful value. mockUsers = [createMockUser()]; mockFetchBodyBattery.mockResolvedValue({ current: null, @@ -468,8 +472,8 @@ describe("POST /api/cron/garmin-sync", () => { expect(mockPbCreate).toHaveBeenCalledWith( expect.objectContaining({ - bodyBatteryCurrent: null, - bodyBatteryYesterdayLow: null, + bodyBatteryCurrent: 100, + bodyBatteryYesterdayLow: 100, }), ); }); diff --git a/src/app/api/cron/garmin-sync/route.ts b/src/app/api/cron/garmin-sync/route.ts index b49d2b0..ac842f8 100644 --- a/src/app/api/cron/garmin-sync/route.ts +++ b/src/app/api/cron/garmin-sync/route.ts @@ -205,13 +205,16 @@ export async function POST(request: Request) { ); // Create DailyLog entry + // Store default value 100 for body battery when Garmin returns null. + // This prevents PocketBase's number field null-to-0 coercion from + // causing the dashboard to display 0 instead of a meaningful value. await pb.collection("dailyLogs").create({ user: user.id, date: today, cycleDay, phase, - bodyBatteryCurrent: bodyBattery.current, - bodyBatteryYesterdayLow: bodyBattery.yesterdayLow, + bodyBatteryCurrent: bodyBattery.current ?? 100, + bodyBatteryYesterdayLow: bodyBattery.yesterdayLow ?? 100, hrvStatus, weekIntensityMinutes, phaseLimit,