recipe suggestion works

pull/23/head
Rayhân HASSOU 1 year ago
parent b98fe71167
commit 663c8bd799

@ -3,4 +3,5 @@ import Recipes from "../../Models/Recipes";
export default interface IRecipesService { export default interface IRecipesService {
getAllRecipes(): Promise<Recipes[]>; getAllRecipes(): Promise<Recipes[]>;
getRecipeById(id: number): Promise<Recipes | null>; getRecipeById(id: number): Promise<Recipes | null>;
getRecipeWithIngredients(ids: string[]): Promise<Recipes[] | null>;
} }

@ -4,13 +4,14 @@ import Recipes from "../../Models/Recipes";
export default class RecipesService implements IRecipesService { export default class RecipesService implements IRecipesService {
private readonly API_URL = "http://leftovers.alwaysdata.net/recipes"; private readonly API_URL = "http://leftovers.alwaysdata.net/recipes";
private readonly IA_URL = "https://codefirst.iut.uca.fr/containers/Sae_LeftOvers-leftovers_ia/getrecipes"
async getAllRecipes(): Promise<Recipes[]> { async getAllRecipes(): Promise<Recipes[]> {
try { try {
const response = await axios.get(this.API_URL); const response = await axios.get(this.API_URL);
return response.data as Recipes[]; return response.data as Recipes[];
} catch (error) { } catch (error) {
throw new Error('Erreur lors de la récupération des ingrédients : ' + error.message); throw new Error('Erreur lors de la récupération des recettes dans getAllRecipes: ' + error.message);
} }
} }
@ -21,8 +22,20 @@ export default class RecipesService implements IRecipesService {
//console.log(response.name); //console.log(response.name);
return response.data as Recipes; return response.data as Recipes;
} catch (error) { } catch (error) {
throw new Error('Erreur lors de la récupération des ingrédients : ' + error.message); throw new Error('Erreur lors de la récupération des recettes dans getRecipeById : ' + error.message);
} }
} }
async getRecipeWithIngredients(ids: string[]): Promise<Recipes[]>{
const recipe: Recipes[] = [];
try {
const response = await axios.get(`${this.IA_URL}/${ids}`);
if(response == null){
return recipe;
}
return response.data as Recipes[];
} catch (error) {
throw new Error('Erreur lors de la récupération des recettes dans getRecipeWithIngredients : ' + error.message);
}
}
} }

@ -5,16 +5,23 @@ import Union_left from '../assets/images/Union_left.png';
import Union_right from '../assets/images/Union_right.png'; import Union_right from '../assets/images/Union_right.png';
import background from '../assets/images/Background.png'; import background from '../assets/images/Background.png';
import ColorContext from '../theme/ColorContext'; import ColorContext from '../theme/ColorContext';
import Recipes from '../Models/Recipes';
interface RecipeElementProps { interface RecipeElementProps {
number: string recipe: Recipes
title: string
textList: {title: string}[]
description: string
duration: string
navigateDetails: () => void navigateDetails: () => void
} }
function convertToHoursMinutes(totalMinutes: number): string {
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
const hoursString = hours > 0 ? `${hours} h` : '';
const minutesString = minutes > 0 ? ` ${minutes} min` : '';
return `${hoursString}${minutesString}`.trim();
}
export default function RecipeElement(props: RecipeElementProps) { export default function RecipeElement(props: RecipeElementProps) {
const {colors} = useContext(ColorContext) const {colors} = useContext(ColorContext)
@ -78,8 +85,8 @@ export default function RecipeElement(props: RecipeElementProps) {
return ( return (
<Pressable style={styles.button} onPress={props.navigateDetails}> <Pressable style={styles.button} onPress={props.navigateDetails}>
<View style={styles.view}> <View style={styles.view}>
<Text style={styles.text}>{props.number}</Text> <Text style={styles.text}>{props.recipe.id}</Text>
<Text style={styles.title}>{props.title}</Text> <Text style={styles.title}>{props.recipe.name}</Text>
<Image source={brochette} style={{width: 100, resizeMode: "contain"}}/> <Image source={brochette} style={{width: 100, resizeMode: "contain"}}/>
<View style={styles.horizontalAlignment}> <View style={styles.horizontalAlignment}>
<Image source={Union_left} style={{width: "25%", marginRight: "3%", resizeMode: "contain"}} /> <Image source={Union_left} style={{width: "25%", marginRight: "3%", resizeMode: "contain"}} />
@ -87,8 +94,8 @@ export default function RecipeElement(props: RecipeElementProps) {
<Image source={Union_right} style={{ width: "25%", marginLeft: "3%", resizeMode: "contain"}} /> <Image source={Union_right} style={{ width: "25%", marginLeft: "3%", resizeMode: "contain"}} />
</View> </View>
<View style={styles.horizontalAlignment}> <View style={styles.horizontalAlignment}>
{props.textList.length > 0 && props.textList.map((source, index) => ( {props.recipe.ingredients.length > 0 && props.recipe.ingredients.map((source, index) => (
<Text key={index} style={styles.smallText}>- {source.title} -</Text> <Text key={index} style={styles.smallText}>- {source.name} -</Text>
))} ))}
</View> </View>
<View style={styles.scrollViewContainer}> <View style={styles.scrollViewContainer}>
@ -98,12 +105,14 @@ export default function RecipeElement(props: RecipeElementProps) {
<Image source={Union_right} style={{width: "27%", marginLeft: "3%", resizeMode: "contain"}}/> <Image source={Union_right} style={{width: "27%", marginLeft: "3%", resizeMode: "contain"}}/>
</View> </View>
<ScrollView style={{marginTop: "3%", overflow: "hidden"}}> <ScrollView style={{marginTop: "3%", overflow: "hidden"}}>
<Text style={styles.smallText}>{props.description}</Text> <Text style={styles.smallText}>{props.recipe.description}</Text>
</ScrollView> </ScrollView>
</View> </View>
<Image source={background} style={{width: "80%", resizeMode: "contain", position: "absolute", zIndex: 1, top: "97.5%"}}></Image> <Image source={background} style={{width: "80%", resizeMode: "contain", position: "absolute", zIndex: 1, top: "97.5%"}}></Image>
<Text style={styles.duration}>{props.duration}</Text> <Text style={styles.duration}>{convertToHoursMinutes(props.recipe.time_to_cook)}</Text>
</View> </View>
</Pressable> </Pressable>
); );
} }

@ -5,9 +5,10 @@ import bracketRight from '../assets/images/angle_bracket_right.png';
import parameter from '../assets/images/parameter.png'; import parameter from '../assets/images/parameter.png';
import FoodElementText from './FoodElementText'; import FoodElementText from './FoodElementText';
import ColorContext from '../theme/ColorContext'; import ColorContext from '../theme/ColorContext';
import Ingredient from '../Models/Ingredient';
interface SelectedIngredientProps { interface SelectedIngredientProps {
ingredientList: {title: string}[] ingredientList: Ingredient[]
onEvent: () => void onEvent: () => void
} }
@ -72,7 +73,7 @@ export default function SelectedIngredient(props: SelectedIngredientProps) {
<Pressable onPress={decreaseCounter}> <Pressable onPress={decreaseCounter}>
<Image source={bracketLeft} style={{width: 40, height: 40, tintColor: colors.cardDetail, resizeMode: "contain"}}/> <Image source={bracketLeft} style={{width: 40, height: 40, tintColor: colors.cardDetail, resizeMode: "contain"}}/>
</Pressable> </Pressable>
<FoodElementText title={props.ingredientList[cpt].title}/> <FoodElementText title={props.ingredientList[cpt].name}/>
<Pressable onPress={increaseCounter}> <Pressable onPress={increaseCounter}>
<Image source={bracketRight} style={{width: 40, height: 40, tintColor: colors.cardDetail, resizeMode: "contain"}}/> <Image source={bracketRight} style={{width: 40, height: 40, tintColor: colors.cardDetail, resizeMode: "contain"}}/>
</Pressable> </Pressable>

@ -15,7 +15,7 @@ export default function IngredientSelection(props) {
const alphabetArray: Array<string> = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]; const alphabetArray: Array<string> = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [response, setResponse] = useState<Ingredient[] | undefined>(undefined); const [response, setResponse] = useState<Ingredient[] | undefined>(undefined);
const [selectedIngredients, setSelectedIngredients] = useState([]); const [selectedIngredients, setSelectedIngredients] = useState<Ingredient[]>([]);
const ingredientService = new IngredientService(); const ingredientService = new IngredientService();
const {colors} = useContext(ColorContext); const {colors} = useContext(ColorContext);
const [availableSize, setAvailableSize] = useState(0); const [availableSize, setAvailableSize] = useState(0);
@ -63,7 +63,9 @@ const loadIngredients = async () => {
const AvailableItem = ({ value }: { value: Ingredient }) => ( const AvailableItem = ({ value }: { value: Ingredient }) => (
<> <>
<View style={styles.horizontalAlignment}> <View style={styles.horizontalAlignment}>
<FoodElementText title={value.name}/> <Pressable onPress={() => SelectIngredient(value)}>
<FoodElementText title={value.name}/>
</Pressable>
<Pressable onPress={() => SelectIngredient(value)}> <Pressable onPress={() => SelectIngredient(value)}>
<Image source={plus} style={{ width: 20, height: 20, tintColor: colors.cardDetail }} /> <Image source={plus} style={{ width: 20, height: 20, tintColor: colors.cardDetail }} />
</Pressable> </Pressable>
@ -75,7 +77,9 @@ const loadIngredients = async () => {
const ChooseItem = ({ value }: { value: Ingredient }) => ( const ChooseItem = ({ value }: { value: Ingredient }) => (
<> <>
<View style={styles.horizontalAlignment}> <View style={styles.horizontalAlignment}>
<FoodElementText title={value.name} /> <Pressable onPress={() => RemoveIngredient(value.id)}>
<FoodElementText title={value.name} />
</Pressable>
<Pressable onPress={() => RemoveIngredient(value.id)}> <Pressable onPress={() => RemoveIngredient(value.id)}>
<Image source={moins} style={{ width: 20, height: 20, tintColor: colors.cardDetail }} /> <Image source={moins} style={{ width: 20, height: 20, tintColor: colors.cardDetail }} />
</Pressable> </Pressable>
@ -256,7 +260,12 @@ const loadIngredients = async () => {
</View> </View>
</View> </View>
<View style={{marginTop: "8%"}}></View> <View style={{marginTop: "8%"}}></View>
<ValidateButton title="Find a recipe" image="validate.png" colour={colors.buttonMain} backColour={colors.cardBackground} todo={() => props.navigation.navigate("RecipeSuggestion")}/> <ValidateButton title="Find a recipe" image="validate.png"
colour={colors.buttonMain}
backColour={colors.cardBackground}
todo={() => props.navigation.navigate('RecipeSuggestion',
{ingredients: selectedIngredients })}
/>
<View style={{marginBottom: "20%"}}></View> <View style={{marginBottom: "20%"}}></View>
</LinearGradient> </LinearGradient>
</SafeAreaProvider> </SafeAreaProvider>

@ -1,4 +1,4 @@
import React, { useState, useContext } from 'react'; import React, { useState, useContext, useEffect } from 'react';
import {View, StyleSheet, Text, Image, Pressable, useWindowDimensions, ScrollView} from 'react-native'; import {View, StyleSheet, Text, Image, Pressable, useWindowDimensions, ScrollView} from 'react-native';
import {SafeAreaProvider } from 'react-native-safe-area-context'; import {SafeAreaProvider } from 'react-native-safe-area-context';
import {Modal, Portal, PaperProvider} from 'react-native-paper'; import {Modal, Portal, PaperProvider} from 'react-native-paper';
@ -15,24 +15,35 @@ import bracketLeft from '../assets/images/angle_bracket_left.png';
import bracketRight from '../assets/images/angle_bracket_right.png'; import bracketRight from '../assets/images/angle_bracket_right.png';
import plus from '../assets/images/plus_small.png'; import plus from '../assets/images/plus_small.png';
import minus from '../assets/images/minus.png'; import minus from '../assets/images/minus.png';
import { useNavigation } from '@react-navigation/native';
import RecipesServices from '../Services/Recipes/RecipesServices';
import Recipes from '../Models/Recipes';
import Ingredient from '../Models/Ingredient';
export default function RecipeSuggestion(props) { export default function RecipeSuggestion({ route }) {
const {colors} = useContext(ColorContext) const {colors} = useContext(ColorContext)
const [visible, setVisible] = React.useState(false); const [visible, setVisible] = React.useState(false);
const [visibleFilters, setVisibleFilters] = React.useState(false); const [visibleFilters, setVisibleFilters] = React.useState(false);
const [visibleIngredients, setVisibleIngredients] = React.useState(true); const [visibleIngredients, setVisibleIngredients] = React.useState(true);
const [minCpt, setMinCpt] = useState(0); const [minCpt, setMinCpt] = useState(0);
const [maxCpt, setMaxCpt] = useState(4); const [maxCpt, setMaxCpt] = useState(4);
const ingredientList = [{title: "Steak"}, {title: "Sheep Ribs"}, {title: "Rabbit Thigh"}, {title: "Ham"}, {title: "Cream (Liquid)"}, {title: "Pepper Bell"}]
const ingredientListV2 = [{title: "Smoked Salmon"}, {title: "Tomato"}, {title: "Carrot"}]
const limitedList = ingredientList.slice(minCpt, maxCpt);
const [colorIngredients, setColorIngredients] = useState("#59BDCD"); const [colorIngredients, setColorIngredients] = useState("#59BDCD");
const [colorFilters, setColorFilters] = useState(colors.cardDetail); const [colorFilters, setColorFilters] = useState(colors.cardDetail);
const [isLoading, setIsLoading] = useState(true);
const [response, setResponse] = useState<Recipes[] | undefined>(undefined);
const [selectedRecipes, setSelectedRecipes] = useState([]);
console.log(selectedRecipes);
const recipeService = new RecipesServices();
const { ingredients } = route.params;
const limitedList = ingredients.slice(minCpt, maxCpt);
let selectedIngredients: string[];
const navigation = useNavigation();
const die = [{value: "Gluten free"}, {value: "Porkless"}, {value: "Gluten free"}, {value: "Porkless"}] const die = [{value: "Gluten free"}, {value: "Porkless"}, {value: "Gluten free"}, {value: "Porkless"}]
const all = [] const all = []
const containerStyle = { const containerStyle = {
//minHeight: useWindowDimensions().height/2, //minHeight: useWindowDimensions().height/2,
//width: useWindowDimensions().width, //width: useWindowDimensions().width,
@ -64,13 +75,13 @@ export default function RecipeSuggestion(props) {
setMaxCpt(maxCpt - 4) setMaxCpt(maxCpt - 4)
} }
else{ else{
setMaxCpt(ingredientList.length+ingredientList.length%4) setMaxCpt(ingredients.length+ingredients.length%4)
let cpt=ingredientList.length-(ingredientList.length%4) let cpt=ingredients.length-(ingredients.length%4)
setMinCpt(cpt) setMinCpt(cpt)
} }
} }
const increaseCounter = () => { const increaseCounter = () => {
if (maxCpt < ingredientList.length) { if (maxCpt < ingredients.length) {
setMinCpt(minCpt + 4); setMinCpt(minCpt + 4);
setMaxCpt(maxCpt + 4) setMaxCpt(maxCpt + 4)
} }
@ -79,6 +90,33 @@ export default function RecipeSuggestion(props) {
setMaxCpt(4) setMaxCpt(4)
} }
} }
const getIngredientsIds = (ingredients) => {
console.log("Liste des ingredients : " + ingredients[0].name)
selectedIngredients = ingredients.map(ingredient => ingredient.id).join(':');
return selectedIngredients;
};
const loadRecipes = async () => {
const ids: string[] = getIngredientsIds(ingredients);
console.log("Les ids des ingredients : " + ids);
try {
const recipes: Recipes[] = await recipeService.getRecipeWithIngredients(ids);
console.log("Les recettes trouvé : " + recipes)
if(recipes === null){
setSelectedRecipes(recipes);
}
} catch (error) {
console.log(error);
} finally {
setIsLoading(false);
}
};
useEffect(() => {
console.log("Je passe ici (Ingredient Selection)")
loadRecipes();
}, []);
const styles = StyleSheet.create({ const styles = StyleSheet.create({
linearGradient: { linearGradient: {
@ -138,15 +176,31 @@ export default function RecipeSuggestion(props) {
}, },
}); });
const recipeElements = Array.isArray(selectedRecipes) && selectedRecipes.length === 0 ? (
<Text>No recipes</Text>
) : (
<View>
{selectedRecipes.map((recipe, index) => (
<View style={{ marginRight: 10 }} key={recipe.id}>
<RecipeElement
key={recipe.id}
recipe={recipe}
navigateDetails={goDetails}
/>
</View>
))}
</View>
);
const ingredientElements = limitedList.map((source, index) => ( const ingredientElements = limitedList.map((source, index) => (
<View style={[styles.horizontalAlignment, {marginVertical: "3%"}]}> <View style={[styles.horizontalAlignment, {marginVertical: "3%"}]} key={index}>
<FoodElementTextSimple title={source.title}/> <FoodElementTextSimple title={source.name}/>
<Image source={plus} style={{width: 20, resizeMode: "contain", tintColor: colors.cardDetail}}/> <Image source={plus} style={{width: 20, resizeMode: "contain", tintColor: colors.cardDetail}}/>
<Image source={minus} style={{width: 20, resizeMode: "contain", tintColor: colors.cardDetail}}/> <Image source={minus} style={{width: 20, resizeMode: "contain", tintColor: colors.cardDetail}}/>
</View> </View>
)); ));
const goDetails = () => props.navigation.navigate("RecipeDetails") const goDetails = () => navigation.navigate("RecipeDetails")
return ( return (
<SafeAreaProvider style={{flex: 1}}> <SafeAreaProvider style={{flex: 1}}>
@ -155,19 +209,13 @@ export default function RecipeSuggestion(props) {
<LinearGradient colors={[colors.primary, colors.primaryComplement]} style={[styles.linearGradient, {minHeight: useWindowDimensions().height}]}> <LinearGradient colors={[colors.primary, colors.primaryComplement]} style={[styles.linearGradient, {minHeight: useWindowDimensions().height}]}>
<View style={{marginTop: "6%"}}/> <View style={{marginTop: "6%"}}/>
<SelectedIngredient <SelectedIngredient
ingredientList={ingredientList} ingredientList={ingredients}
onEvent={handleChildEvent}/> onEvent={handleChildEvent}/>
<ScrollView style={{marginTop: "6%"}} horizontal={true}> <ScrollView style={{ marginTop: "6%" }} horizontal={true}>
<View style={{marginHorizontal: 10}}/> <View style={{ marginHorizontal: 10 }} />
<RecipeElement {recipeElements}
number="63" <View style={{ marginHorizontal: 10 }} />
title="Meat Stick" </ScrollView>
textList={ingredientList}
description="Delicious stick with 4 meats. Accessible for beginners. 20 min or less to cook."
duration="17 min"
navigateDetails={goDetails}/>
<View style={{marginHorizontal: 10}}/>
</ScrollView>
<View style={{marginBottom: "20%"}}/> <View style={{marginBottom: "20%"}}/>
</LinearGradient> </LinearGradient>
</ScrollView> </ScrollView>
@ -202,7 +250,7 @@ export default function RecipeSuggestion(props) {
<View style={{marginTop: "3%"}}/> <View style={{marginTop: "3%"}}/>
<ListWithoutSelect title="Allergies" content={all}></ListWithoutSelect> <ListWithoutSelect title="Allergies" content={all}></ListWithoutSelect>
<View style={{marginTop: "3%"}}/> <View style={{marginTop: "3%"}}/>
<ValidateButton title="Change Filters" image="update.png" colour={colors.buttonDetail} backColour={colors.buttonBackground} todo={() => props.navigation.navigate("FiltersSelection")}></ValidateButton> <ValidateButton title="Change Filters" image="update.png" colour={colors.buttonDetail} backColour={colors.buttonBackground} todo={() => navigation.navigate("FiltersSelection")}></ValidateButton>
</View> </View>
<View style={{marginTop: "6%"}}/> <View style={{marginTop: "6%"}}/>
<View> <View>

Loading…
Cancel
Save