feat: initial project scaffold with Watch companion app

This commit is contained in:
2026-08-04 17:28:06 +02:00
parent adbb4f01c5
commit 43b6467efb
65 changed files with 6361 additions and 166 deletions
@@ -0,0 +1,42 @@
import { useState } from "react";
import WatchConnectivity from "../../modules/watch-connectivity";
import type { WorkoutSet } from "@types/workout";
type SyncResult = { status: string } | { error: string };
export function useSyncWorkout() {
const [isSyncing, setIsSyncing] = useState(false);
const sendWorkoutToWatch = async (
workoutId: string,
name: string | null,
poolLength: number,
sets: WorkoutSet[]
): Promise<SyncResult> => {
setIsSyncing(true);
try {
const plan = {
id: workoutId,
name: name ?? "Workout",
poolLength,
sets: sets.map((s) => ({
stroke: s.stroke,
distancePerRep: s.distancePerRep,
repCount: s.repCount,
restType: s.restType,
restDuration: s.restDuration,
targetTime: s.targetTime ?? null,
})),
};
const result = await WatchConnectivity.sendWorkoutPlan(plan);
return result as SyncResult;
} catch (error: any) {
return { error: error.message ?? "Failed to sync" };
} finally {
setIsSyncing(false);
}
};
return { isSyncing, sendWorkoutToWatch };
}
@@ -0,0 +1,38 @@
import { useState, useEffect } from "react";
import WatchConnectivity from "../../modules/watch-connectivity";
type WatchConnectionStatus = "connected" | "disconnected" | "pending";
export function useWatchConnection() {
const [status, setStatus] = useState<WatchConnectionStatus>("pending");
const [isPaired, setIsPaired] = useState(false);
const [isInstalled, setIsInstalled] = useState(false);
useEffect(() => {
checkStatus();
const interval = setInterval(checkStatus, 5000);
return () => clearInterval(interval);
}, []);
const checkStatus = async () => {
try {
const supported = await WatchConnectivity.isSupported();
if (!supported) {
setStatus("disconnected");
return;
}
const paired = await WatchConnectivity.isPaired();
const installed = await WatchConnectivity.isWatchAppInstalled();
const reachable = await WatchConnectivity.isReachable();
setIsPaired(paired);
setIsInstalled(installed);
setStatus(reachable ? "connected" : "disconnected");
} catch {
setStatus("disconnected");
}
};
return { status, isPaired, isInstalled };
}
@@ -0,0 +1,26 @@
import { useState, useEffect } from "react";
import WatchConnectivity from "../../modules/watch-connectivity";
export function useWatchReachability() {
const [isReachable, setIsReachable] = useState(false);
useEffect(() => {
checkReachability();
const interval = setInterval(checkReachability, 5000);
return () => clearInterval(interval);
}, []);
const checkReachability = async () => {
try {
const supported = await WatchConnectivity.isSupported();
if (supported) {
const reachable = await WatchConnectivity.isReachable();
setIsReachable(reachable);
}
} catch {
setIsReachable(false);
}
};
return isReachable;
}