1 Commits
v1.0.6 ... main

Author SHA1 Message Date
81632a4275 Fix: Fitbit screen showed no data after a successful sync
All checks were successful
Build & Release APK / build (push) Successful in 2m4s
load() caches by endpoint for the session, so the post-sync refresh
re-served the pre-sync (empty) summary. Sync now invalidates the
fitbit cache keys — the watermark before reading, summary+latest after
uploading — so the refetch actually hits the server.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-08 00:03:17 -07:00
2 changed files with 10 additions and 1 deletions

View File

@@ -98,6 +98,11 @@ export function clearCache() {
cache = {}; cache = {};
} }
/* drop specific endpoints from the cache so the next load() refetches */
export function invalidate(...keys: EpKey[]) {
for (const k of keys) delete cache[k];
}
/* ---- auth context ---- */ /* ---- auth context ---- */
interface AuthCtx { interface AuthCtx {

View File

@@ -2,7 +2,7 @@
Android-only: react-native-health-connect is loaded lazily so the module's Android-only: react-native-health-connect is loaded lazily so the module's
absence (iOS, Expo Go) never crashes the app. */ absence (iOS, Expo Go) never crashes the app. */
import { Platform } from 'react-native'; import { Platform } from 'react-native';
import { FITBIT_SYNC_URL, load, postJson } from './api'; import { FITBIT_SYNC_URL, invalidate, load, postJson } from './api';
export interface SyncResult { export interface SyncResult {
ok: boolean; ok: boolean;
@@ -90,6 +90,7 @@ export async function syncFitbit(onProgress?: (msg: string) => void): Promise<Sy
await requestPermission(READ_PERMISSIONS.map((r) => ({ accessType: 'read', recordType: r }))); await requestPermission(READ_PERMISSIONS.map((r) => ({ accessType: 'read', recordType: r })));
say('Checking server watermark…'); say('Checking server watermark…');
invalidate('fitbitLatest'); // watermark must be fresh, never the session-cached copy
const latest = await load<{ const latest = await load<{
samples: Record<string, string | null>; samples: Record<string, string | null>;
daily: Record<string, string | null>; daily: Record<string, string | null>;
@@ -182,6 +183,9 @@ export async function syncFitbit(onProgress?: (msg: string) => void): Promise<Sy
ns += res.samples; nd += res.daily; nl += res.sleep; ns += res.samples; nd += res.daily; nl += res.sleep;
} }
// new rows exist server-side — cached copies of these are now stale
invalidate('fitbitSummary', 'fitbitLatest');
return { return {
ok: true, samples: ns, daily: nd, sleep: nl, ok: true, samples: ns, daily: nd, sleep: nl,
message: `Synced ${ns} samples, ${nd} daily rows, ${nl} sleep sessions`, message: `Synced ${ns} samples, ${nd} daily rows, ${nl} sleep sessions`,