"use client"; import { useEffect, useState } from "react"; type NutritionTotals = { calories: number; protein: number; carbs: number; fat: number; }; type NutritionGoals = { caloriesKcal: number | null; proteinG: number | null; carbsG: number | null; fatG: number | null; } | null; type NutritionCoverage = { calories: number; protein: number; carbs: number; fat: number; }; type NutritionResponse = { totals: NutritionTotals; dailyAverage: NutritionTotals; unknownCount: number; goals: NutritionGoals; coverage: NutritionCoverage; }; interface WeeklyNutritionBarProps { weekStart: string; } type BarItem = { label: string; value: number; goal: number | null; unit: string; percentage: number; colorClass: string; }; export function WeeklyNutritionBar({ weekStart }: WeeklyNutritionBarProps) { const [data, setData] = useState(null); useEffect(() => { fetch(`/api/v1/meal-plans/${weekStart}/nutrition`) .then((res) => (res.ok ? res.json() : null)) .then((json) => setData(json)) .catch(() => setData(null)); }, [weekStart]); if (!data || !data.goals) return null; const { dailyAverage, goals, coverage, unknownCount } = data; const bars: BarItem[] = [ { label: "Calories", value: dailyAverage.calories, goal: goals.caloriesKcal, unit: "kcal", percentage: coverage.calories, colorClass: "bg-orange-500", }, { label: "Protein", value: dailyAverage.protein, goal: goals.proteinG, unit: "g", percentage: coverage.protein, colorClass: "bg-blue-500", }, { label: "Carbs", value: dailyAverage.carbs, goal: goals.carbsG, unit: "g", percentage: coverage.carbs, colorClass: "bg-green-500", }, { label: "Fat", value: dailyAverage.fat, goal: goals.fatG, unit: "g", percentage: coverage.fat, colorClass: "bg-yellow-500", }, ]; return (

Daily average vs. your goals

{bars.map((bar) => { if (bar.goal == null) return null; const width = Math.min(bar.percentage, 100); return (
{bar.label} {bar.value} / {bar.goal} {bar.unit}
); })} {unknownCount > 0 && (

{unknownCount} planned {unknownCount === 1 ? "meal" : "meals"} missing nutrition data — estimate it from the recipe page for a more accurate picture.

)}
); }