Files
workout_watcher/frontend/src/features/workout/hooks.ts
T
Artem Kashaev 800dee31b2 Add boto3 dependency and update exercise/machine assets
- Added boto3 as a dependency in pyproject.toml and uv.lock.
- Introduced multiple new exercise images in various formats (jpg, webp, avif, png).
- Added new machine images to enhance the workout assets library.
2026-05-29 15:50:33 +05:00

104 lines
3.3 KiB
TypeScript

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<WorkoutSetInput> }) => 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,
};
}