fitaiProto/apps/mobile/src/services/fitnessGoals.ts

198 lines
5.2 KiB
TypeScript

import { isAxiosError } from "axios";
import { apiClient, withAuth } from "../api/client";
import { API_ENDPOINTS } from "../config/api";
import log from "../utils/logger";
export interface FitnessGoal {
id: string;
userId: string;
fitnessProfileId?: string;
goalType:
| "weight_target"
| "strength_milestone"
| "endurance_target"
| "flexibility_goal"
| "habit_building"
| "custom";
title: string;
description?: string;
targetValue?: number;
currentValue?: number;
unit?: string;
startDate: string;
targetDate?: string;
completedDate?: string;
status: "active" | "completed" | "abandoned" | "paused";
progress: number;
priority: "low" | "medium" | "high";
notes?: string;
createdAt: string;
updatedAt: string;
}
export interface CreateGoalData {
goalType: FitnessGoal["goalType"];
title: string;
description?: string;
targetValue?: number;
currentValue?: number;
unit?: string;
targetDate?: string;
priority?: FitnessGoal["priority"];
notes?: string;
}
export class FitnessGoalsService {
async getGoals(
userId: string,
token: string | null,
status?: string,
): Promise<FitnessGoal[]> {
try {
const response = await apiClient.get(API_ENDPOINTS.FITNESS_GOALS.LIST, {
params: {
userId,
...(status && status !== "all" ? { status } : {}),
},
...withAuth(token),
});
const result = response.data;
// Handle standardized API response format
// API returns: { success: true, data: [...], meta: {...} }
if (result.success && result.data) {
return Array.isArray(result.data) ? result.data : [];
}
// Fallback for legacy format (direct array)
return Array.isArray(result) ? result : [];
} catch (error) {
if (isAxiosError(error) && error.response) {
throw new Error(`Failed to fetch goals: ${error.response.status}`);
}
log.error("Failed to fetch fitness goals", error);
throw error;
}
}
async createGoal(
goalData: CreateGoalData,
token: string | null,
): Promise<FitnessGoal> {
try {
const response = await apiClient.post(
API_ENDPOINTS.FITNESS_GOALS.CREATE,
goalData,
withAuth(token),
);
const result = response.data;
// Handle standardized API response format
if (result.success && result.data) {
return result.data;
}
// Fallback for legacy format
return result;
} catch (error) {
if (isAxiosError(error)) {
const message =
(error.response?.data as { error?: string } | undefined)?.error ||
(error.response
? `Failed to create goal: ${error.response.status}`
: "Failed to create goal");
throw new Error(message);
}
log.error("Failed to create fitness goal", error);
throw error;
}
}
async updateGoal(
id: string,
updates: Partial<FitnessGoal>,
token: string | null,
): Promise<FitnessGoal> {
try {
const response = await apiClient.put(
API_ENDPOINTS.FITNESS_GOALS.UPDATE(id),
updates,
withAuth(token),
);
const result = response.data;
// Handle standardized API response format
if (result.success && result.data) {
return result.data;
}
// Fallback for legacy format
return result;
} catch (error) {
if (isAxiosError(error) && error.response) {
throw new Error(`Failed to update goal: ${error.response.status}`);
}
log.error("Failed to update fitness goal", error);
throw error;
}
}
async updateProgress(
id: string,
currentValue: number,
token: string | null,
): Promise<FitnessGoal> {
return this.updateGoal(id, { currentValue }, token);
}
async completeGoal(id: string, token: string | null): Promise<FitnessGoal> {
try {
const response = await apiClient.post(
API_ENDPOINTS.FITNESS_GOALS.COMPLETE(id),
{},
withAuth(token),
);
const result = response.data;
// Note: Complete endpoint returns direct object (legacy format)
// Handle standardized API response format (if migrated)
if (result.success && result.data) {
return result.data;
}
// Fallback for legacy format (current implementation)
return result;
} catch (error) {
if (isAxiosError(error) && error.response) {
throw new Error(`Failed to complete goal: ${error.response.status}`);
}
log.error("Failed to complete fitness goal", error);
throw error;
}
}
async deleteGoal(id: string, token: string | null): Promise<void> {
try {
await apiClient.delete(
API_ENDPOINTS.FITNESS_GOALS.DELETE(id),
withAuth(token),
);
// DELETE endpoint returns: { success: true, data: { deleted: true }, meta: {...} }
// No need to parse the result for void return type
} catch (error) {
if (isAxiosError(error) && error.response) {
throw new Error(`Failed to delete goal: ${error.response.status}`);
}
log.error("Failed to delete fitness goal", error);
throw error;
}
}
}
export const fitnessGoalsService = new FitnessGoalsService();