feat(watch): add lap detection via accelerometer and workout sync to phone

This commit is contained in:
2026-08-07 16:35:20 +02:00
parent 00a8220096
commit 48286041c6
8 changed files with 414 additions and 40 deletions
+45
View File
@@ -135,6 +135,51 @@ export async function getWorkoutLaps(workoutId: string) {
return db.select().from(laps).where(eq(laps.workoutId, workoutId));
}
export async function saveWatchCompletedWorkout(data: {
workoutId: string;
duration: number;
totalDistance: number;
calories: number;
laps: Array<{
setPosition: number;
repNumber: number;
distance: number;
duration: number;
heartRate: number;
}>;
}) {
const avgHeartRate =
data.laps.length > 0
? Math.round(data.laps.reduce((sum, l) => sum + (l.heartRate || 0), 0) / data.laps.length)
: 0;
await db
.update(workouts)
.set({
finishedAt: new Date().toISOString(),
totalDuration: data.duration,
totalDistance: data.totalDistance || 0,
calories: data.calories || 0,
avgHeartRate,
source: "watch",
})
.where(eq(workouts.id, data.workoutId));
for (const lap of data.laps) {
await db.insert(laps).values({
id: generateUUID(),
workoutId: data.workoutId,
setPosition: lap.setPosition,
repNumber: lap.repNumber,
distance: lap.distance,
duration: lap.duration,
heartRate: lap.heartRate || null,
strokeCount: null,
swolf: null,
});
}
}
// ─── Stats ───────────────────────────────────────────────────
export async function getWeeklyStats() {
@@ -0,0 +1,36 @@
import { useEffect, useRef } from "react";
import WatchConnectivity from "../../../modules/watch-connectivity";
import { saveWatchCompletedWorkout } from "@db/operations";
export function useWatchWorkoutSync() {
const pollingRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
pollingRef.current = setInterval(async () => {
try {
const events = (await WatchConnectivity.pollEvents()) as any[];
for (const event of events) {
if (event.type === "workoutCompleted") {
console.log("[useWatchWorkoutSync] Received workoutCompleted:", event.workoutId);
await saveWatchCompletedWorkout({
workoutId: event.workoutId,
duration: event.duration ?? 0,
totalDistance: event.totalDistance ?? 0,
calories: event.calories ?? 0,
laps: event.laps ?? [],
});
console.log("[useWatchWorkoutSync] Saved completed workout to DB");
}
}
} catch (error) {
// Silently ignore polling errors
}
}, 2000);
return () => {
if (pollingRef.current) {
clearInterval(pollingRef.current);
}
};
}, []);
}