Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions SparkyFitnessFrontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { ThemeProvider } from '@/contexts/ThemeContext';
import DraggableChatbotButton from '@/components/DraggableChatbotButton';
import AboutDialog from '@/components/AboutDialog';
import NewReleaseDialog from '@/components/NewReleaseDialog';
import NewReleaseDialog, { ReleaseInfo } from '@/components/NewReleaseDialog';
import AppSetup from '@/components/AppSetup';
import { Toaster } from '@/components/ui/toaster';
import {
Expand Down Expand Up @@ -100,7 +100,7 @@ export const ComponentFallback = () => {
};
const Root = () => {
const [showAboutDialog, setShowAboutDialog] = useState(false);
const [latestRelease, setLatestRelease] = useState(null);
const [latestRelease, setLatestRelease] = useState<ReleaseInfo | null>(null);
const [showNewReleaseDialog, setShowNewReleaseDialog] = useState(false);
const { data: appVersion } = useCurrentVersionQuery();
const navigate = useNavigate();
Expand Down
6 changes: 3 additions & 3 deletions SparkyFitnessFrontend/src/api/Chatbot/Chatbot_FoodHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ export const addFoodOption = async (
try {
const { foodOptions, mealType, quantity, unit, entryDate } =
originalMetadata;
const selectedOption = foodOptions[optionIndex];
const selectedOption = foodOptions?.[optionIndex];

if (!selectedOption) {
error(
userLoggingLevel,
`[${transactionId}] Invalid option index:`,
`[${transactionId}] Invalid option index or missing foodOptions:`,
optionIndex
);
return {
Expand Down Expand Up @@ -502,7 +502,7 @@ export const addFoodOption = async (

const calories = Math.round(
(selectedOption.calories || 0) *
(quantity / (selectedOption.serving_size || 100))
((quantity ?? 0) / (selectedOption.serving_size || 100))
);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,11 @@ export const processMeasurementInput = async (

let categoryId: string;
let existingCategory = null;
let categorySearchError: ApiError = null;
let categorySearchError: ApiError = {};
try {
existingCategory = await searchCustomCategory(customMeasurementName);
} catch (err: unknown) {
categorySearchError = err;
categorySearchError = err as ApiError;
}

if (categorySearchError && categorySearchError.code !== 'PGRST116') {
Expand Down Expand Up @@ -220,15 +220,15 @@ export const processMeasurementInput = async (
`Custom category "${customMeasurementName}" not found, creating...`
);
let newCategory = null;
let categoryCreateError: ApiError = null;
let categoryCreateError: ApiError = {};
try {
newCategory = await createCustomCategory({
name: customMeasurementName,
frequency: 'Daily',
measurement_type: 'numeric',
});
} catch (err: unknown) {
categoryCreateError = err;
categoryCreateError = err as ApiError;
}

if (categoryCreateError) {
Expand All @@ -245,7 +245,7 @@ export const processMeasurementInput = async (

// Now insert the custom measurement entry
const valueToLog = measurement.value ?? measurement.systolic;
let customEntryError: ApiError = null;
let customEntryError: ApiError = {};

if (valueToLog === undefined || valueToLog === null) {
error(
Expand All @@ -264,7 +264,7 @@ export const processMeasurementInput = async (
entry_timestamp: new Date().toISOString(),
});
} catch (err: unknown) {
customEntryError = err;
customEntryError = err as ApiError;
}

if (customEntryError) {
Expand Down
39 changes: 21 additions & 18 deletions SparkyFitnessFrontend/src/api/Chatbot/sparkyChatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ export const processUserInput = async (
try {
const jsonMatch = aiResponse.response.match(/```json\n([\s\S]*?)\n```/);
let jsonString = jsonMatch ? jsonMatch[1] : aiResponse.response;
jsonString = stripJsonComments(jsonString); // Strip comments before parsing
jsonString = stripJsonComments(jsonString ?? ''); // Strip comments before parsing

parsedResponse = JSON.parse(jsonString);
info(
Expand Down Expand Up @@ -269,8 +269,8 @@ export const processUserInput = async (
foodResponse.metadata;

const foodOptions = await callAIForFoodOptions(
foodName,
unit,
foodName ?? '',
unit ?? '',
userLoggingLevel,
activeAIServiceSetting as AIService
);
Expand Down Expand Up @@ -348,7 +348,7 @@ export const processUserInput = async (
case 'chat':
return await processChatInput(
parsedResponse.data || {},
parsedResponse.response,
parsedResponse.response ?? '',
userLoggingLevel
);
default: {
Expand Down Expand Up @@ -615,23 +615,26 @@ const extractDateFromInput = (
/(\d{1,2})[/-](\d{1,2})(?:[/-](\d{2,4}))?/
);
if (dateMatch) {
const month = parseInt(dateMatch[1], 10);
const day = parseInt(dateMatch[2], 10);
let year = today.getFullYear();

if (dateMatch[3]) {
year = parseInt(dateMatch[3], 10);
if (year < 100) {
year += 2000;
const [, monthStr, dayStr, yearStr] = dateMatch;
if (monthStr && dayStr) {
const month = parseInt(monthStr, 10);
const day = parseInt(dayStr, 10);
let year = today.getFullYear();

if (yearStr) {
year = parseInt(yearStr, 10);
if (year < 100) {
year += 2000;
}
}
}

if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
const date = new Date(year, month - 1, day);
if (!dateMatch[3] && date > today) {
date.setFullYear(year - 1);
if (month >= 1 && month <= 12 && day >= 1 && day <= 31) {
const date = new Date(year, month - 1, day);
if (!yearStr && date > today) {
date.setFullYear(year - 1);
}
return date.toISOString().split('T')[0];
}
return date.toISOString().split('T')[0];
}
}
return undefined;
Expand Down
30 changes: 19 additions & 11 deletions SparkyFitnessFrontend/src/api/Exercises/exerciseEntryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export const fetchExerciseEntries = async (
sets: ex.sets ? ex.sets : [], // Parse sets if it's a JSON string
exercise_snapshot: {
...ex.exercise_snapshot, // Use the existing snapshot
id: ex.exercise_snapshot.id ?? '',
name: ex.exercise_snapshot.name ?? '',
calories_per_hour: ex.exercise_snapshot.calories_per_hour ?? 0,
category: ex.exercise_snapshot.category ?? '',
equipment: parseJsonArray(ex.exercise_snapshot.equipment),
primary_muscles: parseJsonArray(
ex.exercise_snapshot.primary_muscles
Expand All @@ -47,14 +51,14 @@ export const fetchExerciseEntries = async (
},
activity_details: ex.activity_details
? ex.activity_details.map((detail) => ({
id: detail.id,
key: detail.detail_type,
id: detail.id ?? '',
key: detail.detail_type ?? '',
value:
typeof detail.detail_data === 'object'
? JSON.stringify(detail.detail_data, null, 2)
: String(detail.detail_data),
provider_name: detail.provider_name,
detail_type: detail.detail_type,
detail_type: detail.detail_type ?? '',
}))
: [],
}))
Expand All @@ -66,26 +70,30 @@ export const fetchExerciseEntries = async (
sets: entry.sets ? entry.sets : [], // Parse sets if it's a JSON string
exercise_snapshot: {
...entry.exercise_snapshot, // Use the existing snapshot
equipment: parseJsonArray(entry.exercise_snapshot.equipment),
id: entry.exercise_snapshot?.id ?? '',
name: entry.exercise_snapshot?.name ?? '',
category: entry.exercise_snapshot?.category ?? '',
calories_per_hour: entry.exercise_snapshot?.calories_per_hour ?? 0,
equipment: parseJsonArray(entry.exercise_snapshot?.equipment),
primary_muscles: parseJsonArray(
entry.exercise_snapshot.primary_muscles
entry.exercise_snapshot?.primary_muscles
),
secondary_muscles: parseJsonArray(
entry.exercise_snapshot.secondary_muscles
entry.exercise_snapshot?.secondary_muscles
),
instructions: parseJsonArray(entry.exercise_snapshot.instructions),
images: parseJsonArray(entry.exercise_snapshot.images),
instructions: parseJsonArray(entry.exercise_snapshot?.instructions),
images: parseJsonArray(entry.exercise_snapshot?.images),
},
activity_details: entry.activity_details
? entry.activity_details.map((detail) => ({
id: detail.id,
key: detail.detail_type,
id: detail.id ?? '',
key: detail.detail_type ?? '',
value:
typeof detail.detail_data === 'object'
? JSON.stringify(detail.detail_data, null, 2)
: String(detail.detail_data),
provider_name: detail.provider_name,
detail_type: detail.detail_type,
detail_type: detail.detail_type ?? '',
}))
: [],
};
Expand Down
17 changes: 15 additions & 2 deletions SparkyFitnessFrontend/src/api/Exercises/exerciseSearchService.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { apiCall } from '@/api/api';
import { Exercise } from '@/types/exercises';

interface ExerciseSearchParams {
searchTerm: string;
equipmentFilter?: string;
muscleGroupFilter?: string;
}
export const searchExercises = async (
query: string,
equipmentFilter: string[] = [],
muscleGroupFilter: string[] = []
): Promise<Exercise[]> => {
const params: Record<string, string> = {
const params: ExerciseSearchParams = {
searchTerm: query,
};
if (equipmentFilter.length > 0) {
Expand All @@ -22,6 +27,14 @@ export const searchExercises = async (
return Array.isArray(result) ? result : [];
};

interface ExternalExerciseSearchParams {
query: string;
providerId: string;
providerType: string;
equipmentFilter?: string;
muscleGroupFilter?: string;
limit?: number;
}
export const searchExternalExercises = async (
query: string,
providerId: string,
Expand All @@ -30,7 +43,7 @@ export const searchExternalExercises = async (
muscleGroupFilter: string[] = [],
limit?: number
): Promise<Exercise[]> => {
const params: Record<string, string | number> = {
const params: ExternalExerciseSearchParams = {
query: query,
providerId: providerId,
providerType: providerType,
Expand Down
7 changes: 6 additions & 1 deletion SparkyFitnessFrontend/src/api/Exercises/workoutPresets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,16 @@ export const deleteWorkoutPreset = async (
});
};

interface WorkoutSearchParams {
searchTerm: string;
limit?: number;
}

export const searchWorkoutPresets = async (
searchTerm: string,
limit?: number
): Promise<WorkoutPreset[]> => {
const params: Record<string, string | number> = { searchTerm };
const params: WorkoutSearchParams = { searchTerm };
if (limit !== undefined) {
params.limit = limit;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export const saveFood = async (
// Create new food
// The first variant in the array is always the primary unit for the food
const primaryVariant = variants[0];
if (!primaryVariant) {
throw new Error('Primary variant is undefined');
}
const foodToCreate = {
name: foodData.name,
brand: foodData.brand,
Expand Down
12 changes: 6 additions & 6 deletions SparkyFitnessFrontend/src/api/Foods/fatSecret.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ const parseFoodDescription = (description: string) => {
let serving_unit: string | undefined;

if (servingMatch) {
serving_size = parseFloat(servingMatch[1]);
serving_unit = servingMatch[2].trim();
serving_size = parseFloat(servingMatch[1] ?? '1');
serving_unit = servingMatch[2]?.trim();
}

return {
calories: caloriesMatch ? parseFloat(caloriesMatch[1]) : 0,
fat: fatMatch ? parseFloat(fatMatch[1]) : 0,
carbs: carbsMatch ? parseFloat(carbsMatch[1]) : 0,
protein: proteinMatch ? parseFloat(proteinMatch[1]) : 0,
calories: caloriesMatch ? parseFloat(caloriesMatch[1] ?? '0') : 0,
fat: fatMatch ? parseFloat(fatMatch[1] ?? '0') : 0,
carbs: carbsMatch ? parseFloat(carbsMatch[1] ?? '0') : 0,
protein: proteinMatch ? parseFloat(proteinMatch[1] ?? '0') : 0,
serving_size,
serving_unit,
};
Expand Down
6 changes: 4 additions & 2 deletions SparkyFitnessFrontend/src/api/Foods/mealPlanTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ export const createMealPlanTemplate = async (

export const updateMealPlanTemplate = async (
userId: string,
templateId: string,
templateData: Partial<MealPlanTemplate>,
currentClientDate?: string
): Promise<MealPlanTemplate> => {
return await api.put(`/meal-plan-templates/${templateId}`, {
if (!templateData.id) {
throw new Error('TemplateId is undefined');
}
return await api.put(`/meal-plan-templates/${templateData.id}`, {
Comment thread
Sim-sat marked this conversation as resolved.
body: { ...templateData, userId, currentClientDate },
});
};
Expand Down
7 changes: 6 additions & 1 deletion SparkyFitnessFrontend/src/api/Foods/meals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ export const createMeal = async (mealData: MealPayload): Promise<Meal> => {
return await apiCall(`/meals`, { method: 'POST', body: mealData });
};

interface MealParams {
filter: string;
searchTerm?: string;
}

export const getMeals = async (
filter: MealFilter = 'all',
searchTerm: string = ''
): Promise<Meal[]> => {
let url = `/meals`;
const params: { [key: string]: string } = { filter };
const params: MealParams = { filter };

if (searchTerm) {
url = `/meals/search`;
Expand Down
11 changes: 9 additions & 2 deletions SparkyFitnessFrontend/src/api/Foods/nutrionix.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { toast } from '@/hooks/use-toast';
import { apiCall } from '@/api/api';
import { getErrorMessage } from '@/utils/api';
import { NutritionixItem } from '@/components/FoodSearch/FoodSearch';

interface NutritionixFood {
food_name: string;
Expand Down Expand Up @@ -188,6 +189,9 @@ export const getNutritionixNutrients = async (
);
if (data && data.foods && data.foods.length > 0) {
const food = data.foods[0];
if (!food) {
throw new Error('Food is undefined');
}
return {
name: food.food_name,
brand: food.brand_name || null,
Expand Down Expand Up @@ -228,7 +232,7 @@ export const getNutritionixNutrients = async (
export const getNutritionixBrandedNutrients = async (
nixItemId: string,
defaultFoodDataProviderId: string | null
) => {
): Promise<NutritionixItem | null> => {
if (!defaultFoodDataProviderId) {
toast({
title: 'Error',
Expand Down Expand Up @@ -262,9 +266,12 @@ export const getNutritionixBrandedNutrients = async (
);
if (data && data.foods && data.foods.length > 0) {
const food = data.foods[0];
if (!food) {
throw new Error('Food is undefined');
}
return {
name: food.food_name,
brand: food.brand_name || null,
brand: food.brand_name || '',
calories: food.nf_calories,
protein: food.nf_protein,
carbs: food.nf_total_carbohydrate,
Expand Down
Loading