import type { QueryClient } from "@tanstack/react-query"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ApiError } from "../../api"; import type { CatalogKind, WorkoutSetInput } from "../../types"; import { useAuth } from "../auth/AuthContext"; import { workoutApi } from "./api"; export async function invalidateWorkoutQueries(queryClient: QueryClient) { await Promise.all([ queryClient.invalidateQueries({ queryKey: ["workout", "active"] }), queryClient.invalidateQueries({ queryKey: ["workouts"] }), queryClient.invalidateQueries({ queryKey: ["calories"] }), queryClient.invalidateQueries({ queryKey: ["progression"] }), ]); } export function useActiveWorkout() { const { auth } = useAuth(); return useQuery({ queryKey: ["workout", "active"], queryFn: () => workoutApi.active(auth.accessToken) }); } export function useWorkoutMutations(options: { onStartConflict?: () => void; onFinish?: () => void; onDiscard?: () => void } = {}) { const { auth } = useAuth(); const token = auth.accessToken; const queryClient = useQueryClient(); const refresh = () => invalidateWorkoutQueries(queryClient); const startWorkout = useMutation({ mutationFn: () => workoutApi.start(token), onSuccess: refresh, onError: async (error) => { if (error instanceof ApiError && error.status === 409) { await refresh(); options.onStartConflict?.(); } }, }); const addWorkoutItem = useMutation({ mutationFn: ({ workoutId, sourceId }: { workoutId: string; sourceId: string; kind: CatalogKind }) => workoutApi.addItem(token, workoutId, { activity_source_id: sourceId, exercise_id: null, equipment_id: null, }), onSuccess: refresh, }); const recordWorkoutSet = useMutation({ mutationFn: ({ itemId, payload }: { itemId: string; payload: WorkoutSetInput }) => workoutApi.addSet(token, itemId, payload), onSuccess: refresh, }); const recordWorkoutSetsBatch = useMutation({ mutationFn: ({ itemId, sets }: { itemId: string; sets: WorkoutSetInput[] }) => workoutApi.addSetBatch(token, itemId, sets), onSuccess: refresh, }); const removeWorkoutItem = useMutation({ mutationFn: (itemId: string) => workoutApi.removeItem(token, itemId), onSuccess: refresh, }); const removeWorkoutSet = useMutation({ mutationFn: ({ itemId, setId }: { itemId: string; setId: string }) => workoutApi.removeSet(token, itemId, setId), onSuccess: refresh, }); const updateWorkoutSet = useMutation({ mutationFn: ({ setId, payload }: { setId: string; payload: Partial }) => workoutApi.updateSet(token, setId, payload), onSuccess: refresh, }); const finishWorkout = useMutation({ mutationFn: ({ workoutId, notes }: { workoutId: string; notes?: string }) => workoutApi.finish(token, workoutId, notes), onSuccess: async () => { await refresh(); options.onFinish?.(); }, }); const discardWorkout = useMutation({ mutationFn: (workoutId: string) => workoutApi.discard(token, workoutId), onSuccess: async () => { await refresh(); options.onDiscard?.(); }, }); return { startWorkout, addWorkoutItem, recordWorkoutSet, recordWorkoutSetsBatch, removeWorkoutItem, removeWorkoutSet, updateWorkoutSet, finishWorkout, discardWorkout, }; }