user report gtound work
This commit is contained in:
1 parent
1be2de05fa
commit
74f0d0dbed
42 files changed
+8127
-5
No files matched your search
@@ -0,0 +1,190 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useEffect,
|
||||
} from "react";
|
||||
import { useUser, useAuth } from "@clerk/clerk-expo";
|
||||
import {
|
||||
getNutritionByDate,
|
||||
saveDailyNutrition,
|
||||
addMealEntry,
|
||||
getMealEntriesByDate,
|
||||
type NutritionEntry,
|
||||
type MealEntry,
|
||||
} from "../api/nutrition";
|
||||
import log from "../utils/logger";
|
||||
|
||||
interface NutritionContextValue {
|
||||
nutrition: NutritionEntry | null;
|
||||
meals: MealEntry[];
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
calorieGoal: number;
|
||||
todayCalories: number;
|
||||
percentage: number;
|
||||
addMeal: (
|
||||
data: Omit<MealEntry, "id" | "createdAt" | "dailyNutritionId">,
|
||||
) => Promise<void>;
|
||||
updateGoal: (goal: number) => void;
|
||||
refetch: () => Promise<void>;
|
||||
}
|
||||
|
||||
const NutritionContext = createContext<NutritionContextValue | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
export function NutritionProvider({ children }: { children: React.ReactNode }) {
|
||||
const { user } = useUser();
|
||||
const { getToken } = useAuth();
|
||||
const [nutrition, setNutrition] = useState<NutritionEntry | null>(null);
|
||||
const [meals, setMeals] = useState<MealEntry[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
const [calorieGoal, setCalorieGoal] = useState(2000); // Default goal: 2000 cal
|
||||
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
|
||||
const fetchTodayNutrition = useCallback(async () => {
|
||||
if (!user?.id) return;
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
const token = await getToken();
|
||||
|
||||
// Fetch both nutrition data and meal entries
|
||||
const [nutritionData, mealsData] = await Promise.all([
|
||||
getNutritionByDate(today, token),
|
||||
getMealEntriesByDate(today, token),
|
||||
]);
|
||||
|
||||
if (nutritionData) {
|
||||
setNutrition(nutritionData);
|
||||
if (nutritionData.calorieGoal) {
|
||||
setCalorieGoal(nutritionData.calorieGoal);
|
||||
}
|
||||
} else {
|
||||
setNutrition(null);
|
||||
}
|
||||
|
||||
setMeals(mealsData);
|
||||
log.debug("Today's nutrition fetched", {
|
||||
nutritionData,
|
||||
mealsCount: mealsData.length,
|
||||
});
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err : new Error(String(err));
|
||||
log.error("Failed to fetch nutrition", error);
|
||||
setError(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [user?.id, getToken, today]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTodayNutrition();
|
||||
}, [fetchTodayNutrition]);
|
||||
|
||||
const addMeal = useCallback(
|
||||
async (data: Omit<MealEntry, "id" | "createdAt" | "dailyNutritionId">) => {
|
||||
if (!user?.id) return;
|
||||
|
||||
try {
|
||||
const token = await getToken();
|
||||
|
||||
// Add the meal entry
|
||||
const meal = await addMealEntry(data, token);
|
||||
|
||||
// Recalculate total calories
|
||||
const currentTotal = nutrition?.totalCalories || 0;
|
||||
const newTotal = currentTotal + data.calories;
|
||||
|
||||
// Update the daily nutrition
|
||||
const updatedNutrition = await saveDailyNutrition(
|
||||
{
|
||||
date: today,
|
||||
totalCalories: newTotal,
|
||||
calorieGoal,
|
||||
meals: [
|
||||
...(nutrition?.meals || []),
|
||||
{
|
||||
type: data.mealType,
|
||||
name: data.foodName,
|
||||
calories: data.calories,
|
||||
time: new Date().toISOString(),
|
||||
},
|
||||
],
|
||||
},
|
||||
token,
|
||||
);
|
||||
|
||||
setNutrition(updatedNutrition);
|
||||
setMeals([...meals, meal]);
|
||||
log.debug("Meal added successfully", { meal, newTotal });
|
||||
} catch (err) {
|
||||
const error = err instanceof Error ? err : new Error(String(err));
|
||||
log.error("Failed to add meal", error);
|
||||
setError(error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[user?.id, getToken, today, nutrition, calorieGoal, meals],
|
||||
);
|
||||
|
||||
const updateGoal = useCallback(
|
||||
async (goal: number) => {
|
||||
setCalorieGoal(goal);
|
||||
if (user?.id && nutrition) {
|
||||
try {
|
||||
const token = await getToken();
|
||||
await saveDailyNutrition(
|
||||
{
|
||||
date: today,
|
||||
totalCalories: nutrition.totalCalories,
|
||||
calorieGoal: goal,
|
||||
meals: nutrition.meals,
|
||||
},
|
||||
token,
|
||||
);
|
||||
} catch (err) {
|
||||
log.error("Failed to update calorie goal", err);
|
||||
}
|
||||
}
|
||||
},
|
||||
[user?.id, nutrition, today, getToken],
|
||||
);
|
||||
|
||||
const todayCalories = nutrition?.totalCalories || 0;
|
||||
const percentage =
|
||||
calorieGoal > 0 ? Math.round((todayCalories / calorieGoal) * 100) : 0;
|
||||
|
||||
const value: NutritionContextValue = {
|
||||
nutrition,
|
||||
meals,
|
||||
loading,
|
||||
error,
|
||||
calorieGoal,
|
||||
todayCalories,
|
||||
percentage,
|
||||
addMeal,
|
||||
updateGoal,
|
||||
refetch: fetchTodayNutrition,
|
||||
};
|
||||
|
||||
return (
|
||||
<NutritionContext.Provider value={value}>
|
||||
{children}
|
||||
</NutritionContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useNutrition() {
|
||||
const context = useContext(NutritionContext);
|
||||
if (context === undefined) {
|
||||
throw new Error("useNutrition must be used within a NutritionProvider");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
Reference in new issue
Block a user