From f0ab4bafe175c9cc93fb9b657edd1b763902a3ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:16:52 +0000 Subject: [PATCH 1/3] Initial plan From e89c75072fee53f154436a4ab85ea6629d081d58 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:27:39 +0000 Subject: [PATCH 2/3] Implement core Smart Food Insights components and utilities Co-authored-by: RahilKothari9 <110282686+RahilKothari9@users.noreply.github.com> --- src/components/AlternativesSuggestions.jsx | 245 ++++++++++++++++ src/components/FoodInsights.jsx | 260 +++++++++++++++++ src/components/SeasonalRecommendations.jsx | 319 +++++++++++++++++++++ src/components/TemporaryDrawer.jsx | 66 ++++- src/data/seasonalIngredients.js | 199 +++++++++++++ src/utils/nutritionAnalysis.js | 306 ++++++++++++++++++++ 6 files changed, 1380 insertions(+), 15 deletions(-) create mode 100644 src/components/AlternativesSuggestions.jsx create mode 100644 src/components/FoodInsights.jsx create mode 100644 src/components/SeasonalRecommendations.jsx create mode 100644 src/data/seasonalIngredients.js create mode 100644 src/utils/nutritionAnalysis.js diff --git a/src/components/AlternativesSuggestions.jsx b/src/components/AlternativesSuggestions.jsx new file mode 100644 index 0000000..47164e3 --- /dev/null +++ b/src/components/AlternativesSuggestions.jsx @@ -0,0 +1,245 @@ +import React, { useState } from 'react'; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Button, + Typography, + Card, + CardContent, + Box, + Chip, + IconButton, + Grid, + Divider, + Accordion, + AccordionSummary, + AccordionDetails +} from '@mui/material'; +import { + Close as CloseIcon, + ExpandMore as ExpandMoreIcon, + Lightbulb as LightbulbIcon, + TrendingUp as TrendingUpIcon, + Favorite as FavoriteIcon +} from '@mui/icons-material'; +import { analyzeNutrition, suggestHealthierAlternatives } from '../utils/nutritionAnalysis'; + +const AlternativesSuggestions = ({ open, onClose, nutritionData }) => { + const [expanded, setExpanded] = useState(false); + + if (!nutritionData) { + return null; + } + + const analysis = analyzeNutrition(nutritionData); + const alternatives = suggestHealthierAlternatives(nutritionData, analysis); + + const handleAccordionChange = (panel) => (event, isExpanded) => { + setExpanded(isExpanded ? panel : false); + }; + + const getNutrientColor = (category) => { + switch (category) { + case 'Low Sodium': + return '#2196f3'; + case 'Lower Sugar': + return '#9c27b0'; + case 'Calorie Conscious': + return '#ff9800'; + case 'Protein Boost': + return '#4caf50'; + default: + return '#757575'; + } + }; + + return ( + + + + + + Healthier Alternatives & Tips + + + + + + + + + {alternatives.length === 0 ? ( + + + + Great Choice! + + + This meal looks nutritionally balanced. No specific alternatives needed! + + + Keep up the healthy eating habits! 🎉 + + + ) : ( + + + Based on your meal's nutritional profile, here are some suggestions to make it even healthier: + + + {alternatives.map((category, categoryIndex) => ( + + + + } + /> + + + + {category.suggestions.map((suggestion, suggestionIndex) => ( + + + } + sx={{ + backgroundColor: 'transparent', + '&:hover': { backgroundColor: '#f0f0f0' } + }} + > + + + {suggestion.title} + + + Click to see details and benefits + + + + + + + {suggestion.description} + + + + + ✨ Benefit: {suggestion.benefit} + + + + + + + ))} + + + + ))} + + + + {/* General Healthy Eating Tips */} + + + + 💡 General Healthy Eating Tips + + + + + + 🥗 Plate Method + + + Fill half your plate with vegetables, one quarter with lean protein, and one quarter with whole grains. + + + + + + + 🥤 Stay Hydrated + + + Drink plenty of water throughout the day. Sometimes thirst is mistaken for hunger. + + + + + + + 🍎 Color Variety + + + Eat a rainbow of colors to ensure you get a variety of vitamins and antioxidants. + + + + + + + ⏰ Mindful Eating + + + Eat slowly and pay attention to hunger cues. It takes 20 minutes for your brain to register fullness. + + + + + + + + )} + + + + + + + ); +}; + +export default AlternativesSuggestions; \ No newline at end of file diff --git a/src/components/FoodInsights.jsx b/src/components/FoodInsights.jsx new file mode 100644 index 0000000..0538327 --- /dev/null +++ b/src/components/FoodInsights.jsx @@ -0,0 +1,260 @@ +import React, { useState } from 'react'; +import { + Card, + CardContent, + Typography, + Chip, + Box, + Accordion, + AccordionSummary, + AccordionDetails, + Grid, + CircularProgress, + Tooltip, + IconButton +} from '@mui/material'; +import { + ExpandMore as ExpandMoreIcon, + TipsAndUpdates as TipsIcon, + Favorite as HeartIcon, + Warning as WarningIcon, + Info as InfoIcon, + Psychology as InsightIcon +} from '@mui/icons-material'; +import { analyzeNutrition, generateEducationalFacts } from '../utils/nutritionAnalysis'; + +const FoodInsights = ({ nutritionData }) => { + const [expanded, setExpanded] = useState(false); + + if (!nutritionData) { + return null; + } + + const analysis = analyzeNutrition(nutritionData); + const educationalFacts = generateEducationalFacts(nutritionData); + + const handleAccordionChange = (panel) => (event, isExpanded) => { + setExpanded(isExpanded ? panel : false); + }; + + const getHealthScoreColor = (score) => { + if (score >= 90) return '#4caf50'; // Green + if (score >= 80) return '#8bc34a'; // Light green + if (score >= 70) return '#ff9800'; // Orange + return '#f44336'; // Red + }; + + const getInsightIcon = (type) => { + switch (type) { + case 'concern': + return ; + case 'positive': + return ; + case 'suggestion': + return ; + default: + return ; + } + }; + + return ( + + + + + + Smart Food Insights + + + + + Health Score: + + + + + + {analysis.healthGrade} + + + + + + + + {analysis.overallMessage} + + + {/* Quick Insights */} + + + {analysis.positives.map((positive, index) => ( + + } + /> + + ))} + {analysis.concerns.map((concern, index) => ( + + } + /> + + ))} + + + + {/* Macro Ratios */} + {analysis.macroRatios && ( + + + Macronutrient Balance: + + + + Protein: {analysis.macroRatios.proteinPercent}% + + + Carbs: {analysis.macroRatios.carbPercent}% + + + Fats: {analysis.macroRatios.fatPercent}% + + + + )} + + {/* Detailed Insights */} + + }> + + Detailed Insights ({analysis.insights.length}) + + + + + {analysis.insights.map((insight, index) => ( + + + {getInsightIcon(insight.type)} + + + {insight.title} + + + {insight.message} + + {insight.tip && ( + + 💡 Tip: {insight.tip} + + )} + + + + ))} + + + + + {/* Educational Facts */} + + }> + + Did You Know? + + + + + {educationalFacts.map((fact, index) => ( + + + {fact} + + + ))} + + + + + {/* Recommendations */} + {analysis.recommendations.length > 0 && ( + + }> + + Recommendations ({analysis.recommendations.length}) + + + + + {analysis.recommendations.map((recommendation, index) => ( + + + {recommendation} + + + ))} + + + + )} + + + ); +}; + +export default FoodInsights; \ No newline at end of file diff --git a/src/components/SeasonalRecommendations.jsx b/src/components/SeasonalRecommendations.jsx new file mode 100644 index 0000000..c6060f3 --- /dev/null +++ b/src/components/SeasonalRecommendations.jsx @@ -0,0 +1,319 @@ +import React, { useState } from 'react'; +import { + Card, + CardContent, + Typography, + Box, + Grid, + Chip, + Accordion, + AccordionSummary, + AccordionDetails, + Tooltip, + Avatar +} from '@mui/material'; +import { + ExpandMore as ExpandMoreIcon, + Eco as EcoIcon, + LocalFlorist as SpringIcon, + WbSunny as SummerIcon, + Nature as FallIcon, + AcUnit as WinterIcon +} from '@mui/icons-material'; +import { + getCurrentSeason, + getSeasonalIngredients, + suggestSeasonalAlternatives, + getSeasonalEatingTips +} from '../data/seasonalIngredients'; + +const SeasonalRecommendations = ({ currentIngredients = [] }) => { + const [expanded, setExpanded] = useState(false); + const currentSeason = getCurrentSeason(); + const seasonalIngredients = getSeasonalIngredients(); + const seasonalAlternatives = suggestSeasonalAlternatives(currentIngredients); + const seasonalTips = getSeasonalEatingTips(); + + const handleAccordionChange = (panel) => (event, isExpanded) => { + setExpanded(isExpanded ? panel : false); + }; + + const getSeasonIcon = (season) => { + switch (season) { + case 'spring': + return ; + case 'summer': + return ; + case 'fall': + return ; + case 'winter': + return ; + default: + return ; + } + }; + + const getSeasonColor = (season) => { + switch (season) { + case 'spring': + return '#e8f5e8'; + case 'summer': + return '#fff3e0'; + case 'fall': + return '#efebe9'; + case 'winter': + return '#e3f2fd'; + default: + return '#f5f5f5'; + } + }; + + const getSeasonGradient = (season) => { + switch (season) { + case 'spring': + return 'linear-gradient(135deg, #81c784 0%, #4caf50 100%)'; + case 'summer': + return 'linear-gradient(135deg, #ffb74d 0%, #ff9800 100%)'; + case 'fall': + return 'linear-gradient(135deg, #a1887f 0%, #8d6e63 100%)'; + case 'winter': + return 'linear-gradient(135deg, #64b5f6 0%, #2196f3 100%)'; + default: + return 'linear-gradient(135deg, #81c784 0%, #4caf50 100%)'; + } + }; + + return ( + + + + {getSeasonIcon(currentSeason)} + + {currentSeason} Seasonal Recommendations + + + + + + Eating seasonally supports local agriculture and ensures peak nutrition and flavor! + + + {/* Seasonal Alternatives */} + {seasonalAlternatives.map((category, index) => ( + + }> + + + {category.category} + + + {category.description} + + + + + + {category.items.map((item, itemIndex) => ( + + + + 🌱 {item.name} + + + {item.benefits} + + + 💡 {item.preparation} + + + + ))} + + + + ))} + + {/* Seasonal Categories */} + + }> + + What's in Season Now + + + + + {/* Vegetables */} + + + 🥬 Vegetables + + + {seasonalIngredients.vegetables.slice(0, 5).map((vegetable, index) => ( + + + + ))} + + + + {/* Fruits */} + + + 🍎 Fruits + + + {seasonalIngredients.fruits.map((fruit, index) => ( + + + + ))} + + + + {/* Herbs */} + + + 🌿 Herbs & Spices + + + {seasonalIngredients.herbs.map((herb, index) => ( + + + + ))} + + + + + + + {/* Seasonal Eating Tips */} + + }> + + {currentSeason.charAt(0).toUpperCase() + currentSeason.slice(1)} Eating Tips + + + + + {seasonalTips.map((tip, index) => ( + + + 💡 {tip} + + + ))} + + + + + {/* Environmental Benefits */} + + + + Eating seasonally reduces carbon footprint and supports local farmers! 🌍 + + + + + ); +}; + +export default SeasonalRecommendations; \ No newline at end of file diff --git a/src/components/TemporaryDrawer.jsx b/src/components/TemporaryDrawer.jsx index 665c97e..68e935d 100644 --- a/src/components/TemporaryDrawer.jsx +++ b/src/components/TemporaryDrawer.jsx @@ -7,10 +7,14 @@ import { grey } from '@mui/material/colors'; import { styled } from '@mui/material/styles'; import PropTypes from 'prop-types'; import * as React from 'react'; -import { Button } from '@mui/material'; +import { Button, IconButton, Tooltip } from '@mui/material'; +import { TipsAndUpdates as InsightsIcon, Lightbulb as AlternativesIcon } from '@mui/icons-material'; import axios from 'axios'; // Use axios for API calls import '../css/drawer.css'; import { UserAuth } from '../contexts/AuthContext'; +import FoodInsights from './FoodInsights'; +import AlternativesSuggestions from './AlternativesSuggestions'; +import SeasonalRecommendations from './SeasonalRecommendations'; const drawerBleeding = 50; const Root = styled('div')(({ theme }) => ({ @@ -54,6 +58,7 @@ const updateTotalCalories = async (userId, calories, protein, sugar, carbs, fat, function SwipeableEdgeDrawer(props) { const { window } = props; const [open, setOpen] = React.useState(false); + const [showAlternatives, setShowAlternatives] = React.useState(false); const { user } = UserAuth(); // console.log(user) const userId = user.uid; // Replace this with your user ID management @@ -100,21 +105,45 @@ function SwipeableEdgeDrawer(props) {
{recipe.name}

{recipe.name}

- + updateTotalCalories(userId, caloriesAsNumber, proteinAsNumber, sugarAsNumber, carbsAsNumber, fatAsNumber, sodiumAsNumber); + }} + variant="contained" + color="primary" + sx={{ minWidth: 100 }} + > + Eat + + + + + + + + {/* Food Insights Component */} + + + {/* Seasonal Recommendations Component */} +
+ + {/* Alternatives Dialog */} + setShowAlternatives(false)} + nutritionData={recipe} + /> ); } diff --git a/src/data/seasonalIngredients.js b/src/data/seasonalIngredients.js new file mode 100644 index 0000000..50b3044 --- /dev/null +++ b/src/data/seasonalIngredients.js @@ -0,0 +1,199 @@ +// Seasonal ingredients database for providing seasonal alternatives and recommendations + +export const SEASONAL_INGREDIENTS = { + spring: { + vegetables: [ + { name: 'Asparagus', benefits: 'High in folate and vitamin K', preparation: 'Grill or roast for best flavor' }, + { name: 'Artichokes', benefits: 'Rich in fiber and antioxidants', preparation: 'Steam and serve with lemon' }, + { name: 'Peas', benefits: 'Good source of protein and fiber', preparation: 'Add to salads or pasta dishes' }, + { name: 'Spring onions', benefits: 'Mild flavor, rich in vitamin C', preparation: 'Use in stir-fries or as garnish' }, + { name: 'Radishes', benefits: 'Low calories, high in vitamin C', preparation: 'Eat raw in salads or pickle' }, + { name: 'Spinach', benefits: 'Iron and folate powerhouse', preparation: 'Sauté with garlic or add to smoothies' }, + { name: 'Lettuce', benefits: 'Hydrating and low calorie', preparation: 'Perfect for fresh salads' } + ], + fruits: [ + { name: 'Strawberries', benefits: 'High in vitamin C and antioxidants', preparation: 'Eat fresh or add to yogurt' }, + { name: 'Rhubarb', benefits: 'Good source of fiber', preparation: 'Stew with minimal sugar' }, + { name: 'Apricots', benefits: 'Rich in beta-carotene', preparation: 'Eat fresh or grill for dessert' } + ], + herbs: [ + { name: 'Chives', benefits: 'Adds onion flavor without calories', preparation: 'Sprinkle on eggs or salads' }, + { name: 'Parsley', benefits: 'Rich in vitamin K', preparation: 'Use fresh in salads or as garnish' }, + { name: 'Dill', benefits: 'Good source of calcium', preparation: 'Pairs well with fish and yogurt' } + ] + }, + summer: { + vegetables: [ + { name: 'Tomatoes', benefits: 'High in lycopene and vitamin C', preparation: 'Eat fresh or grill for smokiness' }, + { name: 'Zucchini', benefits: 'Low calorie, high water content', preparation: 'Spiralize as pasta alternative' }, + { name: 'Bell peppers', benefits: 'Vitamin C powerhouse', preparation: 'Stuff with quinoa or eat raw' }, + { name: 'Corn', benefits: 'Good source of fiber', preparation: 'Grill or add to salads' }, + { name: 'Cucumber', benefits: 'Hydrating and cooling', preparation: 'Add to water or make gazpacho' }, + { name: 'Eggplant', benefits: 'High in fiber and antioxidants', preparation: 'Grill or roast until tender' }, + { name: 'Green beans', benefits: 'Rich in vitamin K', preparation: 'Steam lightly to retain crunch' } + ], + fruits: [ + { name: 'Berries', benefits: 'Antioxidant superstars', preparation: 'Eat fresh or freeze for smoothies' }, + { name: 'Peaches', benefits: 'Rich in vitamins A and C', preparation: 'Grill for natural sweetness' }, + { name: 'Watermelon', benefits: 'Hydrating and low calorie', preparation: 'Perfect summer snack' }, + { name: 'Cherries', benefits: 'Anti-inflammatory properties', preparation: 'Eat fresh or add to salads' }, + { name: 'Plums', benefits: 'Good source of vitamin C', preparation: 'Eat fresh or bake into desserts' } + ], + herbs: [ + { name: 'Basil', benefits: 'Anti-inflammatory properties', preparation: 'Make pesto or add to caprese' }, + { name: 'Mint', benefits: 'Aids digestion', preparation: 'Add to water or make tea' }, + { name: 'Oregano', benefits: 'Rich in antioxidants', preparation: 'Use in Mediterranean dishes' } + ] + }, + fall: { + vegetables: [ + { name: 'Pumpkin', benefits: 'High in beta-carotene', preparation: 'Roast seeds for healthy snack' }, + { name: 'Sweet potatoes', benefits: 'Rich in vitamin A and fiber', preparation: 'Bake whole or cube and roast' }, + { name: 'Brussels sprouts', benefits: 'High in vitamin K and C', preparation: 'Roast until crispy edges form' }, + { name: 'Cauliflower', benefits: 'Low carb, high in vitamin C', preparation: 'Rice, mash, or roast whole' }, + { name: 'Beets', benefits: 'Rich in folate and nitrates', preparation: 'Roast or spiralize for salads' }, + { name: 'Carrots', benefits: 'High in beta-carotene', preparation: 'Roast with herbs or eat raw' }, + { name: 'Kale', benefits: 'Nutrient dense superfood', preparation: 'Massage for salads or bake chips' } + ], + fruits: [ + { name: 'Apples', benefits: 'High in fiber and vitamin C', preparation: 'Eat with skin for maximum fiber' }, + { name: 'Pears', benefits: 'Good source of fiber', preparation: 'Poach with cinnamon' }, + { name: 'Cranberries', benefits: 'Rich in antioxidants', preparation: 'Add to salads or make sauce' }, + { name: 'Pomegranate', benefits: 'Antioxidant powerhouse', preparation: 'Sprinkle seeds on yogurt' } + ], + herbs: [ + { name: 'Sage', benefits: 'May improve brain function', preparation: 'Crisp in butter for pasta' }, + { name: 'Rosemary', benefits: 'Rich in antioxidants', preparation: 'Roast with vegetables' }, + { name: 'Thyme', benefits: 'Antimicrobial properties', preparation: 'Add to roasted meats' } + ] + }, + winter: { + vegetables: [ + { name: 'Cabbage', benefits: 'High in vitamin C and K', preparation: 'Make slaw or ferment into sauerkraut' }, + { name: 'Leeks', benefits: 'Good source of vitamin K', preparation: 'Add to soups and stews' }, + { name: 'Parsnips', benefits: 'High in fiber and folate', preparation: 'Roast or mash as potato alternative' }, + { name: 'Turnips', benefits: 'Low calorie, high in vitamin C', preparation: 'Roast or add to stews' }, + { name: 'Winter squash', benefits: 'Rich in vitamin A', preparation: 'Roast and use in soups' }, + { name: 'Collard greens', benefits: 'Calcium and vitamin K rich', preparation: 'Braise with garlic' } + ], + fruits: [ + { name: 'Citrus fruits', benefits: 'Vitamin C boost for immunity', preparation: 'Eat fresh or add to water' }, + { name: 'Persimmons', benefits: 'Rich in vitamins A and C', preparation: 'Eat fresh or add to salads' }, + { name: 'Kiwi', benefits: 'More vitamin C than oranges', preparation: 'Eat whole or add to smoothies' } + ], + herbs: [ + { name: 'Bay leaves', benefits: 'Anti-inflammatory properties', preparation: 'Add to soups and stews' }, + { name: 'Cinnamon', benefits: 'May help regulate blood sugar', preparation: 'Add to oats or coffee' }, + { name: 'Ginger', benefits: 'Aids digestion and reduces inflammation', preparation: 'Make tea or add to stir-fries' } + ] + } +}; + +/** + * Gets current season based on the current month + * @returns {string} Current season + */ +export const getCurrentSeason = () => { + const month = new Date().getMonth() + 1; // getMonth() returns 0-11 + + if (month >= 3 && month <= 5) return 'spring'; + if (month >= 6 && month <= 8) return 'summer'; + if (month >= 9 && month <= 11) return 'fall'; + return 'winter'; +}; + +/** + * Gets seasonal ingredients for a specific season + * @param {string} season - The season to get ingredients for + * @returns {Object} Seasonal ingredients object + */ +export const getSeasonalIngredients = (season = getCurrentSeason()) => { + return SEASONAL_INGREDIENTS[season] || SEASONAL_INGREDIENTS[getCurrentSeason()]; +}; + +/** + * Suggests seasonal alternatives based on current ingredients + * @param {Array} currentIngredients - Array of current ingredients + * @param {string} season - Optional season, defaults to current + * @returns {Array} Array of seasonal suggestions + */ +export const suggestSeasonalAlternatives = (currentIngredients = [], season = getCurrentSeason()) => { + const seasonal = getSeasonalIngredients(season); + const suggestions = []; + + // Common ingredient mappings to seasonal alternatives + const seasonalMappings = { + spring: { + 'lettuce': seasonal.vegetables.find(v => v.name === 'Spinach'), + 'onion': seasonal.vegetables.find(v => v.name === 'Spring onions'), + 'berries': seasonal.fruits.find(f => f.name === 'Strawberries') + }, + summer: { + 'pasta': { name: 'Zucchini noodles', benefits: 'Lower carb alternative', preparation: 'Spiralize zucchini' }, + 'potato': seasonal.vegetables.find(v => v.name === 'Zucchini'), + 'apple': seasonal.fruits.find(f => f.name === 'Peaches') + }, + fall: { + 'potato': seasonal.vegetables.find(v => v.name === 'Sweet potatoes'), + 'rice': { name: 'Cauliflower rice', benefits: 'Lower carb, more nutrients', preparation: 'Pulse cauliflower in food processor' }, + 'banana': seasonal.fruits.find(f => f.name === 'Apples') + }, + winter: { + 'lettuce': seasonal.vegetables.find(v => v.name === 'Cabbage'), + 'potato': seasonal.vegetables.find(v => v.name === 'Parsnips'), + 'orange': seasonal.fruits.find(f => f.name === 'Citrus fruits') + } + }; + + // Generate suggestions based on season + const currentSeason = season || getCurrentSeason(); + const seasonalBenefits = { + spring: 'Spring ingredients are fresh and help detoxify after winter. They\'re rich in vitamins and perfect for renewal.', + summer: 'Summer produce is hydrating and cooling. High water content helps maintain hydration in hot weather.', + fall: 'Fall ingredients are warming and rich in nutrients to prepare your body for winter. Great sources of vitamin A and fiber.', + winter: 'Winter produce boosts immunity with vitamin C and provides warming, grounding nutrients.' + }; + + suggestions.push({ + category: `${currentSeason.charAt(0).toUpperCase() + currentSeason.slice(1)} Favorites`, + description: seasonalBenefits[currentSeason], + items: [ + ...seasonal.vegetables.slice(0, 3), + ...seasonal.fruits.slice(0, 2) + ] + }); + + return suggestions; +}; + +/** + * Gets seasonal eating tips based on current season + * @param {string} season - Optional season, defaults to current + * @returns {Array} Array of seasonal eating tips + */ +export const getSeasonalEatingTips = (season = getCurrentSeason()) => { + const tips = { + spring: [ + "Focus on detoxifying foods like leafy greens and asparagus", + "Take advantage of fresh herbs to reduce salt usage", + "Enjoy lighter meals as the weather warms up" + ], + summer: [ + "Stay hydrated with water-rich foods like cucumber and watermelon", + "Grill vegetables to enhance their natural flavors", + "Choose cooling foods and avoid heavy, hot meals" + ], + fall: [ + "Incorporate warming spices like cinnamon and ginger", + "Focus on fiber-rich foods to support digestive health", + "Use seasonal squashes as healthy carb alternatives" + ], + winter: [ + "Boost immunity with vitamin C-rich citrus fruits", + "Include warming foods like ginger and root vegetables", + "Make hearty soups and stews with seasonal vegetables" + ] + }; + + return tips[season] || tips[getCurrentSeason()]; +}; \ No newline at end of file diff --git a/src/utils/nutritionAnalysis.js b/src/utils/nutritionAnalysis.js new file mode 100644 index 0000000..0828d76 --- /dev/null +++ b/src/utils/nutritionAnalysis.js @@ -0,0 +1,306 @@ +// Nutrition analysis utilities for food insights and recommendations + +// Recommended daily values and thresholds for analysis +const DAILY_LIMITS = { + calories: 2000, + sodium: 2300, // mg + saturatedFat: 20, // g (assuming 10% of total fats are saturated) + sugars: 50, // g + protein: 50, // g minimum + fats: 65 // g +}; + +// Thresholds for classifying foods as high/low in nutrients (per serving) +const HIGH_THRESHOLDS = { + sodium: 400, // mg per serving + sugars: 15, // g per serving + calories: 400, // calories per serving + fats: 15 // g per serving +}; + +/** + * Analyzes nutrition data and identifies potentially unhealthy aspects + * @param {Object} nutritionData - The nutrition data object + * @returns {Object} Analysis results with insights and recommendations + */ +export const analyzeNutrition = (nutritionData) => { + const analysis = { + concerns: [], + positives: [], + recommendations: [], + healthScore: 100, // Start with perfect score and deduct points + insights: [] + }; + + const { calories, protein, carbs, sugars, fats, sodium } = nutritionData; + + // Convert string values to numbers + const numericData = { + calories: parseFloat(calories) || 0, + protein: parseFloat(protein) || 0, + carbs: parseFloat(carbs) || 0, + sugars: parseFloat(sugars) || 0, + fats: parseFloat(fats) || 0, + sodium: parseFloat(sodium) || 0 + }; + + // Analyze sodium content + if (numericData.sodium > HIGH_THRESHOLDS.sodium) { + analysis.concerns.push('High Sodium'); + analysis.recommendations.push('Consider choosing low-sodium alternatives or reducing portion size'); + analysis.healthScore -= 20; + analysis.insights.push({ + type: 'concern', + title: 'High Sodium Alert', + message: `This meal contains ${numericData.sodium}mg of sodium. High sodium intake can contribute to high blood pressure.`, + tip: 'Try using herbs and spices instead of salt for flavoring.' + }); + } else if (numericData.sodium < 140) { + analysis.positives.push('Low Sodium'); + analysis.insights.push({ + type: 'positive', + title: 'Heart-Healthy Choice', + message: 'This meal is low in sodium, which is great for heart health!' + }); + } + + // Analyze sugar content + if (numericData.sugars > HIGH_THRESHOLDS.sugars) { + analysis.concerns.push('High Sugar'); + analysis.recommendations.push('Look for alternatives with natural sugars or reduce portion size'); + analysis.healthScore -= 15; + analysis.insights.push({ + type: 'concern', + title: 'Sugar Watch', + message: `This meal contains ${numericData.sugars}g of sugar. Consider pairing with protein to help stabilize blood sugar.`, + tip: 'Choose fruits over processed sweets for natural sweetness.' + }); + } + + // Analyze calorie content + if (numericData.calories > HIGH_THRESHOLDS.calories) { + analysis.insights.push({ + type: 'info', + title: 'Calorie Dense', + message: `This is a calorie-dense meal (${numericData.calories} calories). Great for post-workout or when you need sustained energy.` + }); + if (numericData.calories > 600) { + analysis.concerns.push('Very High Calories'); + analysis.healthScore -= 10; + } + } else if (numericData.calories < 200) { + analysis.insights.push({ + type: 'info', + title: 'Light Meal', + message: 'This is a light meal. Consider adding protein or healthy fats for more satiety.' + }); + } + + // Analyze protein content + if (numericData.protein > 15) { + analysis.positives.push('Good Protein Source'); + analysis.insights.push({ + type: 'positive', + title: 'Protein Power', + message: `Excellent protein content (${numericData.protein}g)! Protein helps with muscle maintenance and satiety.` + }); + } else if (numericData.protein < 5) { + analysis.recommendations.push('Consider adding a protein source like nuts, beans, or lean meat'); + analysis.insights.push({ + type: 'suggestion', + title: 'Boost Your Protein', + message: 'This meal is low in protein. Adding protein can help you feel full longer.', + tip: 'Try adding Greek yogurt, nuts, or beans to increase protein content.' + }); + } + + // Analyze fat content + if (numericData.fats > HIGH_THRESHOLDS.fats) { + analysis.insights.push({ + type: 'info', + title: 'Fat Content', + message: `This meal is relatively high in fats (${numericData.fats}g). If these are healthy fats from sources like avocado or nuts, that's great!` + }); + } + + // Calculate macronutrient ratios + const totalMacros = numericData.protein + numericData.carbs + numericData.fats; + if (totalMacros > 0) { + const proteinPercent = Math.round((numericData.protein / totalMacros) * 100); + const carbPercent = Math.round((numericData.carbs / totalMacros) * 100); + const fatPercent = Math.round((numericData.fats / totalMacros) * 100); + + analysis.macroRatios = { proteinPercent, carbPercent, fatPercent }; + + // Provide insights on macro balance + if (proteinPercent >= 25) { + analysis.insights.push({ + type: 'positive', + title: 'Well-Balanced Protein', + message: `Great protein balance (${proteinPercent}% of macros)!` + }); + } + } + + // Overall health score interpretation + if (analysis.healthScore >= 90) { + analysis.healthGrade = 'A'; + analysis.overallMessage = 'Excellent nutritional choice!'; + } else if (analysis.healthScore >= 80) { + analysis.healthGrade = 'B'; + analysis.overallMessage = 'Good nutritional choice with room for improvement.'; + } else if (analysis.healthScore >= 70) { + analysis.healthGrade = 'C'; + analysis.overallMessage = 'Decent choice, but consider healthier alternatives.'; + } else { + analysis.healthGrade = 'D'; + analysis.overallMessage = 'Consider choosing a healthier alternative.'; + } + + return analysis; +}; + +/** + * Suggests healthier alternatives based on nutrition analysis + * @param {Object} nutritionData - The original nutrition data + * @param {Object} analysis - The nutrition analysis results + * @returns {Array} Array of alternative suggestions + */ +export const suggestHealthierAlternatives = (nutritionData, analysis) => { + const alternatives = []; + + // High sodium alternatives + if (analysis.concerns.includes('High Sodium')) { + alternatives.push({ + category: 'Low Sodium', + suggestions: [ + { + title: 'Use herbs and spices', + description: 'Replace salt with garlic, herbs, lemon juice, or vinegar for flavor', + benefit: 'Reduces sodium by up to 300mg per serving' + }, + { + title: 'Choose fresh over processed', + description: 'Opt for fresh vegetables instead of canned or pickled ones', + benefit: 'Can reduce sodium by 200-400mg' + }, + { + title: 'Rinse canned foods', + description: 'Rinse canned beans or vegetables to remove excess sodium', + benefit: 'Reduces sodium by up to 40%' + } + ] + }); + } + + // High sugar alternatives + if (analysis.concerns.includes('High Sugar')) { + alternatives.push({ + category: 'Lower Sugar', + suggestions: [ + { + title: 'Add fiber', + description: 'Include more vegetables or whole grains to slow sugar absorption', + benefit: 'Helps stabilize blood sugar levels' + }, + { + title: 'Natural sweeteners', + description: 'Use fruits like berries or dates instead of added sugars', + benefit: 'Provides antioxidants along with natural sweetness' + }, + { + title: 'Portion control', + description: 'Enjoy a smaller portion and add protein or healthy fats', + benefit: 'Reduces sugar intake while maintaining satisfaction' + } + ] + }); + } + + // High calorie alternatives + if (analysis.concerns.includes('Very High Calories')) { + alternatives.push({ + category: 'Calorie Conscious', + suggestions: [ + { + title: 'Bulk up with vegetables', + description: 'Add more non-starchy vegetables to increase volume with fewer calories', + benefit: 'Maintains portion size while reducing calories by 100-200' + }, + { + title: 'Cooking method swap', + description: 'Try grilling, steaming, or baking instead of frying', + benefit: 'Can reduce calories by 150-300 per serving' + } + ] + }); + } + + // Low protein suggestions + if (analysis.recommendations.some(rec => rec.includes('protein'))) { + alternatives.push({ + category: 'Protein Boost', + suggestions: [ + { + title: 'Add Greek yogurt', + description: 'Include a side of Greek yogurt or use it as a topping', + benefit: 'Adds 15-20g of protein' + }, + { + title: 'Sprinkle nuts or seeds', + description: 'Top your meal with almonds, walnuts, or chia seeds', + benefit: 'Adds 5-10g of protein plus healthy fats' + }, + { + title: 'Include legumes', + description: 'Add beans, lentils, or chickpeas to your meal', + benefit: 'Adds 10-15g of protein plus fiber' + } + ] + }); + } + + return alternatives; +}; + +/** + * Generates educational "Did you know?" facts based on nutrition data + * @param {Object} nutritionData - The nutrition data + * @returns {Array} Array of educational facts + */ +export const generateEducationalFacts = (nutritionData) => { + const facts = [ + "Did you know? Protein helps you feel full longer because it takes more energy to digest than carbs or fats.", + "Did you know? The average American consumes 3,400mg of sodium daily - 50% more than recommended!", + "Did you know? Fiber from vegetables helps slow sugar absorption, preventing blood sugar spikes.", + "Did you know? Eating colorful foods ensures you get a variety of antioxidants and nutrients.", + "Did you know? Healthy fats from nuts, avocados, and fish are essential for brain function.", + "Did you know? Your taste buds adapt to less salt within 2-3 weeks of reducing sodium intake." + ]; + + // Select relevant facts based on the nutrition data + const relevantFacts = []; + const { protein, sodium, sugars } = nutritionData; + + if (parseFloat(protein) > 15) { + relevantFacts.push("Did you know? This meal's high protein content will help maintain stable blood sugar and keep you satisfied longer!"); + } + + if (parseFloat(sodium) > 400) { + relevantFacts.push("Did you know? Reducing sodium intake by just 400mg daily can significantly lower blood pressure in many people."); + } + + if (parseFloat(sugars) < 10) { + relevantFacts.push("Did you know? Keeping sugar intake low like this meal helps maintain steady energy levels throughout the day!"); + } + + // Add 2-3 random facts if we don't have enough relevant ones + while (relevantFacts.length < 3) { + const randomFact = facts[Math.floor(Math.random() * facts.length)]; + if (!relevantFacts.includes(randomFact)) { + relevantFacts.push(randomFact); + } + } + + return relevantFacts.slice(0, 3); +}; \ No newline at end of file From 13836b8392a681dff67c1d1713b51b259c11004f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:32:54 +0000 Subject: [PATCH 3/3] Complete Smart Food Insights implementation with visual indicators and educational tooltips Co-authored-by: RahilKothari9 <110282686+RahilKothari9@users.noreply.github.com> --- src/components/EducationalTooltip.jsx | 53 +++++++++++++ src/components/FoodInsights.jsx | 59 ++++++++++++++- src/components/NutritionBadge.jsx | 62 +++++++++++++++ src/components/NutritionDashboard.jsx | 80 +++++++++++++++++++- src/components/NutritionQualityIndicator.jsx | 52 +++++++++++++ src/components/TemporaryDrawer.jsx | 63 +++++++++++++-- 6 files changed, 358 insertions(+), 11 deletions(-) create mode 100644 src/components/EducationalTooltip.jsx create mode 100644 src/components/NutritionBadge.jsx create mode 100644 src/components/NutritionQualityIndicator.jsx diff --git a/src/components/EducationalTooltip.jsx b/src/components/EducationalTooltip.jsx new file mode 100644 index 0000000..b094675 --- /dev/null +++ b/src/components/EducationalTooltip.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Tooltip, IconButton, Typography, Box } from '@mui/material'; +import { HelpOutline as HelpIcon } from '@mui/icons-material'; + +const EducationalTooltip = ({ + title, + content, + learnMore = null, + icon = , + placement = "top" +}) => { + const tooltipContent = ( + + + {title} + + + {content} + + {learnMore && ( + + 💡 {learnMore} + + )} + + ); + + return ( + + + {icon} + + + ); +}; + +export default EducationalTooltip; \ No newline at end of file diff --git a/src/components/FoodInsights.jsx b/src/components/FoodInsights.jsx index 0538327..2a7ead7 100644 --- a/src/components/FoodInsights.jsx +++ b/src/components/FoodInsights.jsx @@ -11,7 +11,8 @@ import { Grid, CircularProgress, Tooltip, - IconButton + IconButton, + Divider } from '@mui/material'; import { ExpandMore as ExpandMoreIcon, @@ -19,9 +20,11 @@ import { Favorite as HeartIcon, Warning as WarningIcon, Info as InfoIcon, - Psychology as InsightIcon + Psychology as InsightIcon, + Visibility as VisibilityIcon } from '@mui/icons-material'; import { analyzeNutrition, generateEducationalFacts } from '../utils/nutritionAnalysis'; +import NutritionQualityIndicator from './NutritionQualityIndicator'; const FoodInsights = ({ nutritionData }) => { const [expanded, setExpanded] = useState(false); @@ -147,6 +150,58 @@ const FoodInsights = ({ nutritionData }) => { )} + {/* Visual Nutrition Quality Indicators */} + + }> + + + Nutrition Quality Breakdown + + + + + + + + + + + + + + + + + + {/* Detailed Insights */} { + if (!nutritionData) return null; + + const analysis = analyzeNutrition(nutritionData); + + const getBadgeColor = (grade) => { + switch (grade) { + case 'A': + return { backgroundColor: '#4caf50', color: 'white' }; + case 'B': + return { backgroundColor: '#8bc34a', color: 'white' }; + case 'C': + return { backgroundColor: '#ff9800', color: 'white' }; + case 'D': + return { backgroundColor: '#f44336', color: 'white' }; + default: + return { backgroundColor: '#757575', color: 'white' }; + } + }; + + const badgeSize = size === 'small' ? '24px' : size === 'large' ? '40px' : '32px'; + const fontSize = size === 'small' ? '0.75rem' : size === 'large' ? '1.25rem' : '1rem'; + + return ( + + + {analysis.healthGrade} + + {size !== 'small' && ( + + Nutrition Score: {analysis.healthScore}/100 + + )} + + ); +}; + +export default NutritionBadge; \ No newline at end of file diff --git a/src/components/NutritionDashboard.jsx b/src/components/NutritionDashboard.jsx index be43fa0..66d69e5 100644 --- a/src/components/NutritionDashboard.jsx +++ b/src/components/NutritionDashboard.jsx @@ -1,11 +1,13 @@ import { useState, useEffect } from 'react'; -import { Box, Card, CardContent, Typography, LinearProgress, Grid } from '@mui/material'; -import { FitnessCenter, Restaurant, Fastfood, WaterDrop, Icecream, Apple } from '@mui/icons-material'; +import { Box, Card, CardContent, Typography, LinearProgress, Grid, Chip } from '@mui/material'; +import { FitnessCenter, Restaurant, Fastfood, WaterDrop, Icecream, Apple, TipsAndUpdates } from '@mui/icons-material'; import axios from 'axios'; +import { analyzeNutrition, generateEducationalFacts } from '../utils/nutritionAnalysis'; const Dashboard = ({ userId }) => { const [nutritionStats, setNutritionStats] = useState([]); const [calorieHistory, setCalorieHistory] = useState([]); + const [dailyInsights, setDailyInsights] = useState(null); // Fetch the data from your backend const fetchUserData = async () => { @@ -23,6 +25,20 @@ const Dashboard = ({ userId }) => { { name: 'Sugars', value: totalSugars, icon: , color: 'pink', max: 150 }, { name: 'Fats', value: totalFats, icon: , color: 'green', max: 180 }, ]); + + // Generate daily insights + const dailyNutritionData = { + calories: totalCalories, + protein: totalProtein, + carbs: totalCarbs, + sugars: totalSugars, + fats: totalFats, + sodium: totalSodium + }; + + const analysis = analyzeNutrition(dailyNutritionData); + const facts = generateEducationalFacts(dailyNutritionData); + setDailyInsights({ analysis, facts }); } // Fetch calorie history (last 3 days) @@ -92,6 +108,66 @@ const Dashboard = ({ userId }) => { + + {/* Daily Insights Card */} + {dailyInsights && ( + + + + + Today's Nutrition Insights + + + {/* Health Score and Grade */} + + + Overall Health Score: {dailyInsights.analysis.healthScore}/100 + + + + + + {dailyInsights.analysis.overallMessage} + + + {/* Positive aspects and concerns */} + + + {dailyInsights.analysis.positives.map((positive, index) => ( + + + + ))} + {dailyInsights.analysis.concerns.map((concern, index) => ( + + + + ))} + + + + {/* Educational fact */} + {dailyInsights.facts.length > 0 && ( + + + {dailyInsights.facts[0]} + + + )} + + + )} ); }; diff --git a/src/components/NutritionQualityIndicator.jsx b/src/components/NutritionQualityIndicator.jsx new file mode 100644 index 0000000..29029d1 --- /dev/null +++ b/src/components/NutritionQualityIndicator.jsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { Box, Typography, LinearProgress, Tooltip } from '@mui/material'; + +const NutritionQualityIndicator = ({ label, value, max, unit = '', color = 'primary', showProgress = true }) => { + const numericValue = parseFloat(value) || 0; + const percentage = Math.min((numericValue / max) * 100, 100); + + const getColorByPercentage = (percent) => { + if (percent <= 30) return '#4caf50'; // Green - low + if (percent <= 60) return '#ff9800'; // Orange - medium + return '#f44336'; // Red - high + }; + + const progressColor = color === 'auto' ? getColorByPercentage(percentage) : undefined; + + return ( + + + + {label} + + + {numericValue}{unit} + + + + {showProgress && ( + + + + )} + + + Max recommended: {max}{unit} + + + ); +}; + +export default NutritionQualityIndicator; \ No newline at end of file diff --git a/src/components/TemporaryDrawer.jsx b/src/components/TemporaryDrawer.jsx index 68e935d..a894d9b 100644 --- a/src/components/TemporaryDrawer.jsx +++ b/src/components/TemporaryDrawer.jsx @@ -15,6 +15,8 @@ import { UserAuth } from '../contexts/AuthContext'; import FoodInsights from './FoodInsights'; import AlternativesSuggestions from './AlternativesSuggestions'; import SeasonalRecommendations from './SeasonalRecommendations'; +import EducationalTooltip from './EducationalTooltip'; +import NutritionBadge from './NutritionBadge'; const drawerBleeding = 50; const Root = styled('div')(({ theme }) => ({ @@ -104,7 +106,12 @@ function SwipeableEdgeDrawer(props) {
{recipe.name} -

{recipe.name}

+ + {/* Meal title with nutrition badge */} + +

{recipe.name}

+ +
{/* Action buttons row */} @@ -188,12 +195,54 @@ function SwipeableEdgeDrawer(props) { {/*

Per 100 grams:

*/}
    -
  • Calories: {recipe.calories}
  • -
  • Protein: {recipe.protein} g
  • -
  • Carbs: {recipe.carbs} g
  • -
  • Sugars: {recipe.sugars} g
  • -
  • Fats: {recipe.fats} g
  • -
  • Sodium: {recipe.sodium} mg
  • +
  • + Calories: {recipe.calories} + +
  • +
  • + Protein: {recipe.protein} g + +
  • +
  • + Carbs: {recipe.carbs} g + +
  • +
  • + Sugars: {recipe.sugars} g + +
  • +
  • + Fats: {recipe.fats} g + +
  • +
  • + Sodium: {recipe.sodium} mg + +