healthy-meals-core 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bmr.d.ts +3 -0
- package/dist/bmr.js +14 -0
- package/dist/dailyMealPlanGenerator.d.ts +3 -0
- package/dist/dailyMealPlanGenerator.js +211 -0
- package/dist/data/detailed-recipes-bs.json +417 -0
- package/dist/data/detailed-recipes.json +744 -0
- package/dist/foodConversion.d.ts +55 -0
- package/dist/foodConversion.js +200 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +27 -0
- package/dist/planner.d.ts +2 -0
- package/dist/planner.js +24 -0
- package/dist/recipeBasedMealPlanGenerator.d.ts +17 -0
- package/dist/recipeBasedMealPlanGenerator.js +255 -0
- package/dist/recipeService.d.ts +28 -0
- package/dist/recipeService.js +136 -0
- package/dist/rules/cholesterol.d.ts +2 -0
- package/dist/rules/cholesterol.js +7 -0
- package/dist/rules/diabetes.d.ts +2 -0
- package/dist/rules/diabetes.js +7 -0
- package/dist/rules/fattyLiver.d.ts +2 -0
- package/dist/rules/fattyLiver.js +7 -0
- package/dist/rules/index.d.ts +7 -0
- package/dist/rules/index.js +47 -0
- package/dist/rules/lowCarb.d.ts +2 -0
- package/dist/rules/lowCarb.js +7 -0
- package/dist/rules/triglycerides.d.ts +2 -0
- package/dist/rules/triglycerides.js +7 -0
- package/dist/src/bmr.d.ts +3 -0
- package/dist/src/bmr.js +13 -0
- package/dist/src/dailyMealPlanGenerator.d.ts +3 -0
- package/dist/src/dailyMealPlanGenerator.js +210 -0
- package/dist/src/foodConversion.d.ts +55 -0
- package/dist/src/foodConversion.js +199 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +27 -0
- package/dist/src/planner.d.ts +2 -0
- package/dist/src/planner.js +23 -0
- package/dist/src/recipeBasedMealPlanGenerator.d.ts +17 -0
- package/dist/src/recipeBasedMealPlanGenerator.js +254 -0
- package/dist/src/recipeService.d.ts +28 -0
- package/dist/src/recipeService.js +136 -0
- package/dist/src/rules/cholesterol.d.ts +2 -0
- package/dist/src/rules/cholesterol.js +6 -0
- package/dist/src/rules/diabetes.d.ts +2 -0
- package/dist/src/rules/diabetes.js +6 -0
- package/dist/src/rules/fattyLiver.d.ts +2 -0
- package/dist/src/rules/fattyLiver.js +6 -0
- package/dist/src/rules/index.d.ts +7 -0
- package/dist/src/rules/index.js +46 -0
- package/dist/src/rules/lowCarb.d.ts +2 -0
- package/dist/src/rules/lowCarb.js +6 -0
- package/dist/src/rules/triglycerides.d.ts +2 -0
- package/dist/src/rules/triglycerides.js +6 -0
- package/dist/src/types/firestore.d.ts +100 -0
- package/dist/src/types/firestore.js +2 -0
- package/dist/src/types/openfoodfacts.d.ts +113 -0
- package/dist/src/types/openfoodfacts.js +3 -0
- package/dist/src/types/recipe.d.ts +36 -0
- package/dist/src/types/recipe.js +2 -0
- package/dist/src/types.d.ts +24 -0
- package/dist/src/types.js +2 -0
- package/dist/src/variety.d.ts +17 -0
- package/dist/src/variety.js +129 -0
- package/dist/src/weeklyMealPlanGenerator.d.ts +3 -0
- package/dist/src/weeklyMealPlanGenerator.js +468 -0
- package/dist/src/weeklyPlanner.d.ts +12 -0
- package/dist/src/weeklyPlanner.js +31 -0
- package/dist/types/firestore.d.ts +100 -0
- package/dist/types/firestore.js +2 -0
- package/dist/types/openfoodfacts.d.ts +113 -0
- package/dist/types/openfoodfacts.js +3 -0
- package/dist/types/recipe.d.ts +36 -0
- package/dist/types/recipe.js +2 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.js +2 -0
- package/dist/variety.d.ts +17 -0
- package/dist/variety.js +130 -0
- package/dist/weeklyMealPlanGenerator.d.ts +3 -0
- package/dist/weeklyMealPlanGenerator.js +469 -0
- package/dist/weeklyPlanner.d.ts +12 -0
- package/dist/weeklyPlanner.js +32 -0
- package/package.json +66 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.recipeService = exports.RecipeService = void 0;
|
|
7
|
+
const detailed_recipes_json_1 = __importDefault(require("../data/detailed-recipes.json"));
|
|
8
|
+
const detailed_recipes_bs_json_1 = __importDefault(require("../data/detailed-recipes-bs.json"));
|
|
9
|
+
class RecipeService {
|
|
10
|
+
constructor(locale = 'en') {
|
|
11
|
+
this.currentLocale = 'en';
|
|
12
|
+
this.recipes = detailed_recipes_json_1.default;
|
|
13
|
+
this.recipesBS = detailed_recipes_bs_json_1.default;
|
|
14
|
+
this.currentLocale = locale;
|
|
15
|
+
}
|
|
16
|
+
setLocale(locale) {
|
|
17
|
+
this.currentLocale = locale;
|
|
18
|
+
}
|
|
19
|
+
getCurrentRecipes() {
|
|
20
|
+
return this.currentLocale === 'bs' ? this.recipesBS : this.recipes;
|
|
21
|
+
}
|
|
22
|
+
getAllRecipes() {
|
|
23
|
+
return this.getCurrentRecipes();
|
|
24
|
+
}
|
|
25
|
+
getRecipeById(id) {
|
|
26
|
+
return this.getCurrentRecipes().find(recipe => recipe.id === id);
|
|
27
|
+
}
|
|
28
|
+
getRecipesByCategory(category) {
|
|
29
|
+
return this.getCurrentRecipes().filter(recipe => recipe.category === category);
|
|
30
|
+
}
|
|
31
|
+
filterRecipes(filter) {
|
|
32
|
+
return this.getCurrentRecipes().filter(recipe => {
|
|
33
|
+
if (filter.category && recipe.category !== filter.category) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
if (filter.tags && filter.tags.length > 0) {
|
|
37
|
+
const hasMatchingTag = filter.tags.some(tag => recipe.tags.includes(tag));
|
|
38
|
+
if (!hasMatchingTag) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (filter.maxPrepTime && recipe.prepTime > filter.maxPrepTime) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
if (filter.maxCookTime && recipe.cookTime > filter.maxCookTime) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (filter.difficulty && recipe.difficulty !== filter.difficulty) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (filter.maxCalories && recipe.nutrition.calories > filter.maxCalories) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (filter.minProtein && recipe.nutrition.protein < filter.minProtein) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
getRecipesByTags(tags) {
|
|
61
|
+
return this.filterRecipes({ tags });
|
|
62
|
+
}
|
|
63
|
+
getRecipesForHealthGoals(healthGoals) {
|
|
64
|
+
const relevantTags = healthGoals.map(goal => {
|
|
65
|
+
switch (goal) {
|
|
66
|
+
case 'weight_loss':
|
|
67
|
+
return ['low-carb', 'high-protein', 'low-fat'];
|
|
68
|
+
case 'muscle_gain':
|
|
69
|
+
return ['high-protein'];
|
|
70
|
+
case 'heart_health':
|
|
71
|
+
return ['heart-healthy', 'omega-3', 'cholesterol'];
|
|
72
|
+
case 'diabetes':
|
|
73
|
+
return ['diabetes', 'low-carb'];
|
|
74
|
+
case 'cholesterol':
|
|
75
|
+
return ['cholesterol', 'heart-healthy'];
|
|
76
|
+
case 'fatty_liver':
|
|
77
|
+
return ['fatty_liver', 'low-fat'];
|
|
78
|
+
case 'triglycerides':
|
|
79
|
+
return ['triglycerides', 'omega-3'];
|
|
80
|
+
default:
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}).flat();
|
|
84
|
+
return this.filterRecipes({ tags: relevantTags });
|
|
85
|
+
}
|
|
86
|
+
getRecipesForDietaryRestrictions(restrictions) {
|
|
87
|
+
return this.getCurrentRecipes().filter(recipe => {
|
|
88
|
+
if (restrictions.includes('vegetarian')) {
|
|
89
|
+
return recipe.tags.includes('vegetarian') || recipe.tags.includes('vegan');
|
|
90
|
+
}
|
|
91
|
+
if (restrictions.includes('vegan')) {
|
|
92
|
+
return recipe.tags.includes('vegan');
|
|
93
|
+
}
|
|
94
|
+
if (restrictions.includes('gluten-free')) {
|
|
95
|
+
return recipe.tags.includes('gluten-free');
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
getRandomRecipe(category) {
|
|
101
|
+
const filteredRecipes = category
|
|
102
|
+
? this.getRecipesByCategory(category)
|
|
103
|
+
: this.getCurrentRecipes();
|
|
104
|
+
const randomIndex = Math.floor(Math.random() * filteredRecipes.length);
|
|
105
|
+
return filteredRecipes[randomIndex];
|
|
106
|
+
}
|
|
107
|
+
getWeeklyRecipeSuggestions(healthGoals, dietaryRestrictions) {
|
|
108
|
+
let availableRecipes = this.getCurrentRecipes();
|
|
109
|
+
if (dietaryRestrictions.length > 0) {
|
|
110
|
+
availableRecipes = this.getRecipesForDietaryRestrictions(dietaryRestrictions);
|
|
111
|
+
}
|
|
112
|
+
if (healthGoals.length > 0) {
|
|
113
|
+
const healthRecipes = this.getRecipesForHealthGoals(healthGoals);
|
|
114
|
+
availableRecipes = availableRecipes.filter(recipe => healthRecipes.some(hr => hr.id === recipe.id));
|
|
115
|
+
}
|
|
116
|
+
const breakfast = availableRecipes.filter(r => r.category === 'breakfast').slice(0, 7);
|
|
117
|
+
const lunch = availableRecipes.filter(r => r.category === 'lunch').slice(0, 7);
|
|
118
|
+
const dinner = availableRecipes.filter(r => r.category === 'dinner').slice(0, 7);
|
|
119
|
+
const snack = availableRecipes.filter(r => r.category === 'snack').slice(0, 7);
|
|
120
|
+
return { breakfast, lunch, dinner, snack };
|
|
121
|
+
}
|
|
122
|
+
searchRecipes(query) {
|
|
123
|
+
const lowerQuery = query.toLowerCase();
|
|
124
|
+
return this.getCurrentRecipes().filter(recipe => recipe.name.toLowerCase().includes(lowerQuery) ||
|
|
125
|
+
recipe.ingredients.some(ing => ing.name.toLowerCase().includes(lowerQuery)) ||
|
|
126
|
+
recipe.tags.some(tag => tag.toLowerCase().includes(lowerQuery)));
|
|
127
|
+
}
|
|
128
|
+
getTotalTime(recipe) {
|
|
129
|
+
return recipe.prepTime + recipe.cookTime;
|
|
130
|
+
}
|
|
131
|
+
getRecipesByTotalTime(maxMinutes) {
|
|
132
|
+
return this.recipes.filter(recipe => this.getTotalTime(recipe) <= maxMinutes);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.RecipeService = RecipeService;
|
|
136
|
+
exports.recipeService = new RecipeService();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Recipe, HealthCondition } from '../types';
|
|
2
|
+
export declare function applyHealthRules(recipes: Recipe[], conditions: HealthCondition[]): Recipe[];
|
|
3
|
+
export * from './cholesterol';
|
|
4
|
+
export * from './triglycerides';
|
|
5
|
+
export * from './fattyLiver';
|
|
6
|
+
export * from './diabetes';
|
|
7
|
+
export * from './lowCarb';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.applyHealthRules = applyHealthRules;
|
|
18
|
+
const cholesterol_1 = require("./cholesterol");
|
|
19
|
+
const triglycerides_1 = require("./triglycerides");
|
|
20
|
+
const fattyLiver_1 = require("./fattyLiver");
|
|
21
|
+
const diabetes_1 = require("./diabetes");
|
|
22
|
+
const lowCarb_1 = require("./lowCarb");
|
|
23
|
+
function applyHealthRules(recipes, conditions) {
|
|
24
|
+
let result = recipes;
|
|
25
|
+
if (conditions.includes('cholesterol')) {
|
|
26
|
+
result = (0, cholesterol_1.filterCholesterol)(result);
|
|
27
|
+
}
|
|
28
|
+
if (conditions.includes('triglycerides')) {
|
|
29
|
+
result = (0, triglycerides_1.filterTriglycerides)(result);
|
|
30
|
+
}
|
|
31
|
+
if (conditions.includes('fatty_liver')) {
|
|
32
|
+
result = (0, fattyLiver_1.filterFattyLiver)(result);
|
|
33
|
+
}
|
|
34
|
+
if (conditions.includes('diabetes')) {
|
|
35
|
+
result = (0, diabetes_1.filterDiabetes)(result);
|
|
36
|
+
}
|
|
37
|
+
if (conditions.includes('low_carb')) {
|
|
38
|
+
result = (0, lowCarb_1.filterLowCarb)(result);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
__exportStar(require("./cholesterol"), exports);
|
|
43
|
+
__exportStar(require("./triglycerides"), exports);
|
|
44
|
+
__exportStar(require("./fattyLiver"), exports);
|
|
45
|
+
__exportStar(require("./diabetes"), exports);
|
|
46
|
+
__exportStar(require("./lowCarb"), exports);
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export interface UserProfile {
|
|
2
|
+
uid: string;
|
|
3
|
+
email: string;
|
|
4
|
+
displayName?: string;
|
|
5
|
+
age: number;
|
|
6
|
+
gender: 'male' | 'female' | 'other';
|
|
7
|
+
height: number;
|
|
8
|
+
weight: number;
|
|
9
|
+
activityLevel: 'sedentary' | 'lightly_active' | 'moderately_active' | 'very_active' | 'extremely_active';
|
|
10
|
+
dietaryRestrictions: string[];
|
|
11
|
+
healthGoals: string[];
|
|
12
|
+
allergies: string[];
|
|
13
|
+
preferences: {
|
|
14
|
+
cuisineTypes: string[];
|
|
15
|
+
mealComplexity: 'simple' | 'moderate' | 'complex';
|
|
16
|
+
cookingTime: number;
|
|
17
|
+
};
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
updatedAt: Date;
|
|
20
|
+
}
|
|
21
|
+
export interface Ingredient {
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
quantity: number;
|
|
25
|
+
unit: string;
|
|
26
|
+
calories: number;
|
|
27
|
+
protein: number;
|
|
28
|
+
carbs: number;
|
|
29
|
+
fat: number;
|
|
30
|
+
fiber: number;
|
|
31
|
+
sugar: number;
|
|
32
|
+
sodium: number;
|
|
33
|
+
}
|
|
34
|
+
export interface Meal {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
type: 'breakfast' | 'lunch' | 'dinner' | 'snack';
|
|
38
|
+
ingredients: Ingredient[];
|
|
39
|
+
instructions: string[];
|
|
40
|
+
prepTime: number;
|
|
41
|
+
cookTime: number;
|
|
42
|
+
servings: number;
|
|
43
|
+
nutrition: {
|
|
44
|
+
calories: number;
|
|
45
|
+
protein: number;
|
|
46
|
+
carbs: number;
|
|
47
|
+
fat: number;
|
|
48
|
+
fiber: number;
|
|
49
|
+
sugar: number;
|
|
50
|
+
sodium: number;
|
|
51
|
+
};
|
|
52
|
+
tags: string[];
|
|
53
|
+
difficulty: 'easy' | 'medium' | 'hard';
|
|
54
|
+
createdAt: Date;
|
|
55
|
+
updatedAt: Date;
|
|
56
|
+
}
|
|
57
|
+
export interface DailyMealPlan {
|
|
58
|
+
id: string;
|
|
59
|
+
date: string;
|
|
60
|
+
meals: {
|
|
61
|
+
breakfast?: Meal;
|
|
62
|
+
lunch?: Meal;
|
|
63
|
+
dinner?: Meal;
|
|
64
|
+
snacks?: Meal[];
|
|
65
|
+
};
|
|
66
|
+
totalNutrition: {
|
|
67
|
+
calories: number;
|
|
68
|
+
protein: number;
|
|
69
|
+
carbs: number;
|
|
70
|
+
fat: number;
|
|
71
|
+
fiber: number;
|
|
72
|
+
sugar: number;
|
|
73
|
+
sodium: number;
|
|
74
|
+
};
|
|
75
|
+
createdAt: Date;
|
|
76
|
+
updatedAt: Date;
|
|
77
|
+
}
|
|
78
|
+
export interface MealPlan {
|
|
79
|
+
id: string;
|
|
80
|
+
userId: string;
|
|
81
|
+
name: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
startDate: string;
|
|
84
|
+
endDate: string;
|
|
85
|
+
dailyPlans: DailyMealPlan[];
|
|
86
|
+
meals?: Meal[];
|
|
87
|
+
totalCalories?: number;
|
|
88
|
+
totalProtein?: number;
|
|
89
|
+
totalCarbs?: number;
|
|
90
|
+
totalFat?: number;
|
|
91
|
+
uid?: string;
|
|
92
|
+
goals: {
|
|
93
|
+
dailyCalories: number;
|
|
94
|
+
proteinPercentage: number;
|
|
95
|
+
carbsPercentage: number;
|
|
96
|
+
fatPercentage: number;
|
|
97
|
+
};
|
|
98
|
+
createdAt: Date;
|
|
99
|
+
updatedAt: Date;
|
|
100
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export interface OpenFoodFactsProduct {
|
|
2
|
+
_id: string;
|
|
3
|
+
code: string;
|
|
4
|
+
product_name?: string;
|
|
5
|
+
product_name_en?: string;
|
|
6
|
+
brands?: string;
|
|
7
|
+
categories?: string;
|
|
8
|
+
labels?: string;
|
|
9
|
+
image_url?: string;
|
|
10
|
+
image_front_url?: string;
|
|
11
|
+
image_front_small_url?: string;
|
|
12
|
+
image_nutrition_url?: string;
|
|
13
|
+
image_nutrition_small_url?: string;
|
|
14
|
+
nutriments: Nutriments;
|
|
15
|
+
nutrition_grades?: string;
|
|
16
|
+
ecoscore_grade?: string;
|
|
17
|
+
nova_group?: number;
|
|
18
|
+
serving_size?: string;
|
|
19
|
+
serving_quantity?: number;
|
|
20
|
+
allergens?: string;
|
|
21
|
+
traces?: string;
|
|
22
|
+
ingredients_text?: string;
|
|
23
|
+
ingredients_text_en?: string;
|
|
24
|
+
countries?: string;
|
|
25
|
+
manufacturing_places?: string;
|
|
26
|
+
stores?: string;
|
|
27
|
+
packaging?: string;
|
|
28
|
+
quantity?: string;
|
|
29
|
+
completeness?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface Nutriments {
|
|
32
|
+
energy?: number;
|
|
33
|
+
'energy-kcal'?: number;
|
|
34
|
+
'energy-kj'?: number;
|
|
35
|
+
'energy_100g'?: number;
|
|
36
|
+
'energy-kcal_100g'?: number;
|
|
37
|
+
'energy-kj_100g'?: number;
|
|
38
|
+
fat?: number;
|
|
39
|
+
fat_100g?: number;
|
|
40
|
+
'saturated-fat'?: number;
|
|
41
|
+
'saturated-fat_100g'?: number;
|
|
42
|
+
carbohydrates?: number;
|
|
43
|
+
carbohydrates_100g?: number;
|
|
44
|
+
sugars?: number;
|
|
45
|
+
sugars_100g?: number;
|
|
46
|
+
fiber?: number;
|
|
47
|
+
fiber_100g?: number;
|
|
48
|
+
proteins?: number;
|
|
49
|
+
proteins_100g?: number;
|
|
50
|
+
salt?: number;
|
|
51
|
+
salt_100g?: number;
|
|
52
|
+
sodium?: number;
|
|
53
|
+
sodium_100g?: number;
|
|
54
|
+
'nutrition-score-fr'?: number;
|
|
55
|
+
'nutrition-score-uk'?: number;
|
|
56
|
+
}
|
|
57
|
+
export interface OpenFoodFactsSearchResponse {
|
|
58
|
+
count: number;
|
|
59
|
+
page: number;
|
|
60
|
+
page_count: number;
|
|
61
|
+
page_size: number;
|
|
62
|
+
products: OpenFoodFactsProduct[];
|
|
63
|
+
skip: number;
|
|
64
|
+
}
|
|
65
|
+
export interface OpenFoodFactsProductResponse {
|
|
66
|
+
code: string;
|
|
67
|
+
product: OpenFoodFactsProduct;
|
|
68
|
+
status: number;
|
|
69
|
+
status_verbose: string;
|
|
70
|
+
}
|
|
71
|
+
export interface FoodSearchParams {
|
|
72
|
+
search_terms?: string;
|
|
73
|
+
categories?: string;
|
|
74
|
+
brands?: string;
|
|
75
|
+
countries?: string;
|
|
76
|
+
page?: number;
|
|
77
|
+
page_size?: number;
|
|
78
|
+
sort_by?: 'popularity' | 'product_name' | 'created_t' | 'last_modified_t';
|
|
79
|
+
fields?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface NormalizedFoodItem {
|
|
82
|
+
id: string;
|
|
83
|
+
barcode: string;
|
|
84
|
+
name: string;
|
|
85
|
+
brand?: string;
|
|
86
|
+
imageUrl?: string;
|
|
87
|
+
nutritionPer100g: {
|
|
88
|
+
calories: number;
|
|
89
|
+
protein: number;
|
|
90
|
+
carbs: number;
|
|
91
|
+
fat: number;
|
|
92
|
+
fiber?: number;
|
|
93
|
+
sugar?: number;
|
|
94
|
+
sodium?: number;
|
|
95
|
+
};
|
|
96
|
+
nutritionGrade?: string;
|
|
97
|
+
ecoScore?: string;
|
|
98
|
+
novaGroup?: number;
|
|
99
|
+
servingSize?: string;
|
|
100
|
+
ingredients?: string;
|
|
101
|
+
allergens?: string[];
|
|
102
|
+
categories?: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface FoodSearchFilters {
|
|
105
|
+
category?: string;
|
|
106
|
+
brand?: string;
|
|
107
|
+
nutritionGrade?: string;
|
|
108
|
+
ecoScore?: string;
|
|
109
|
+
novaGroup?: number;
|
|
110
|
+
minProtein?: number;
|
|
111
|
+
maxCalories?: number;
|
|
112
|
+
allergenFree?: string[];
|
|
113
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface RecipeIngredient {
|
|
2
|
+
name: string;
|
|
3
|
+
quantity: number;
|
|
4
|
+
unit: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RecipeNutrition {
|
|
7
|
+
calories: number;
|
|
8
|
+
protein: number;
|
|
9
|
+
carbs: number;
|
|
10
|
+
fat: number;
|
|
11
|
+
fiber: number;
|
|
12
|
+
sugar: number;
|
|
13
|
+
sodium: number;
|
|
14
|
+
}
|
|
15
|
+
export interface Recipe {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
category: 'breakfast' | 'lunch' | 'dinner' | 'snack';
|
|
19
|
+
prepTime: number;
|
|
20
|
+
cookTime: number;
|
|
21
|
+
servings: number;
|
|
22
|
+
difficulty: 'easy' | 'medium' | 'hard';
|
|
23
|
+
ingredients: RecipeIngredient[];
|
|
24
|
+
instructions: string[];
|
|
25
|
+
nutrition: RecipeNutrition;
|
|
26
|
+
tags: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface RecipeFilter {
|
|
29
|
+
category?: 'breakfast' | 'lunch' | 'dinner' | 'snack';
|
|
30
|
+
tags?: string[];
|
|
31
|
+
maxPrepTime?: number;
|
|
32
|
+
maxCookTime?: number;
|
|
33
|
+
difficulty?: 'easy' | 'medium' | 'hard';
|
|
34
|
+
maxCalories?: number;
|
|
35
|
+
minProtein?: number;
|
|
36
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type Gender = 'male' | 'female';
|
|
2
|
+
export interface UserProfile {
|
|
3
|
+
heightCm: number;
|
|
4
|
+
weightKg: number;
|
|
5
|
+
age: number;
|
|
6
|
+
gender: Gender;
|
|
7
|
+
activityLevel: 1.2 | 1.375 | 1.55 | 1.725;
|
|
8
|
+
goals: 'maintain' | 'lose' | 'gain';
|
|
9
|
+
conditions: HealthCondition[];
|
|
10
|
+
}
|
|
11
|
+
export type HealthCondition = 'cholesterol' | 'triglycerides' | 'fatty_liver' | 'diabetes' | 'low_carb';
|
|
12
|
+
export interface Recipe {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
calories: number;
|
|
16
|
+
protein: number;
|
|
17
|
+
fat: number;
|
|
18
|
+
carbs: number;
|
|
19
|
+
tags: HealthCondition[];
|
|
20
|
+
}
|
|
21
|
+
export interface MealPlan {
|
|
22
|
+
dailyCalories: number;
|
|
23
|
+
meals: Recipe[];
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Recipe } from './types';
|
|
2
|
+
export declare function shuffleArray<T>(array: T[]): T[];
|
|
3
|
+
export declare function preventConsecutiveRepeats(meals: Recipe[]): Recipe[];
|
|
4
|
+
export declare function ensureMealVariety(meals: Recipe[], minVariety?: number): Recipe[];
|
|
5
|
+
export declare function calculateMealDiversity(meals: Recipe[]): number;
|
|
6
|
+
export declare function getMealCategory(recipe: Recipe): string;
|
|
7
|
+
export declare function calculateCategoryDiversity(meals: Recipe[]): number;
|
|
8
|
+
export declare function hasConsecutiveRepeats(meals: Recipe[]): boolean;
|
|
9
|
+
export declare function scoreMealPlan(meals: Recipe[]): {
|
|
10
|
+
diversity: number;
|
|
11
|
+
categoryDiversity: number;
|
|
12
|
+
proteinBalance: number;
|
|
13
|
+
calorieDistribution: number;
|
|
14
|
+
noConsecutiveRepeats: number;
|
|
15
|
+
overallScore: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function selectDiverseMeals(availableRecipes: Recipe[], targetCalories: number, previousMeals?: Recipe[]): Recipe[];
|