From a29c5b78ec7caed17270feed2bb9d6d63bc021a3 Mon Sep 17 00:00:00 2001 From: Rayhan Hassou Date: Mon, 27 Nov 2023 09:26:16 +0100 Subject: [PATCH] Optimisation of displaying ingredients, and add filters --- .../Ingredients/IIngredientService.tsx | 7 + .../Ingredients/IngredientsServices.tsx | 33 +++ LeftOvers/Services/IngredientsServices.tsx | 0 LeftOvers/package-lock.json | 29 +++ LeftOvers/package.json | 1 + LeftOvers/screens/IngredientSelection.tsx | 246 ++++++++---------- 6 files changed, 180 insertions(+), 136 deletions(-) create mode 100644 LeftOvers/Services/Ingredients/IIngredientService.tsx create mode 100644 LeftOvers/Services/Ingredients/IngredientsServices.tsx delete mode 100644 LeftOvers/Services/IngredientsServices.tsx diff --git a/LeftOvers/Services/Ingredients/IIngredientService.tsx b/LeftOvers/Services/Ingredients/IIngredientService.tsx new file mode 100644 index 0000000..d8c9339 --- /dev/null +++ b/LeftOvers/Services/Ingredients/IIngredientService.tsx @@ -0,0 +1,7 @@ +import Ingredient from "../../Models/Ingredient"; + +export default interface IIngredientService { + getAllIngredient(): Promise; + getIngredientById(id: Number): Promise; + getIngredientByLetter(id: String): Promise; +} \ No newline at end of file diff --git a/LeftOvers/Services/Ingredients/IngredientsServices.tsx b/LeftOvers/Services/Ingredients/IngredientsServices.tsx new file mode 100644 index 0000000..e247ec2 --- /dev/null +++ b/LeftOvers/Services/Ingredients/IngredientsServices.tsx @@ -0,0 +1,33 @@ +import Ingredient from "../../Models/Ingredient"; +import IIngredientService from "./IIngredientService"; +import axios from 'axios'; + +export default class IngredientService implements IIngredientService { + private readonly API_URL = "http://localhost:3000/ingredients"; + + constructor() {} + + async getAllIngredient(): Promise { + try { + const response = await axios.get(this.API_URL); + return response.data as Ingredient[]; + } catch (error) { + throw new Error('Erreur lors de la récupération des ingrédients : ' + error.message); + } + } + + + async getIngredientById(id: Number): Promise{ + + return; + } + + async getIngredientByLetter(letter: String): Promise{ + try { + const response = await axios.get(`${this.API_URL}/letter/${letter}`); + return response.data as Ingredient[]; + } catch (error) { + throw new Error('Erreur lors de la récupération des ingrédients : ' + error.message); + } + } +} diff --git a/LeftOvers/Services/IngredientsServices.tsx b/LeftOvers/Services/IngredientsServices.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/LeftOvers/package-lock.json b/LeftOvers/package-lock.json index 7798ae6..d1b3f47 100644 --- a/LeftOvers/package-lock.json +++ b/LeftOvers/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@expo/webpack-config": "^19.0.0", "@types/react": "~18.2.14", + "axios": "^1.6.2", "expo": "~49.0.15", "expo-linear-gradient": "~12.3.0", "expo-splash-screen": "~0.20.5", @@ -6735,6 +6736,29 @@ "node": ">= 4.0.0" } }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -14620,6 +14644,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", diff --git a/LeftOvers/package.json b/LeftOvers/package.json index 64c0047..daf41d1 100644 --- a/LeftOvers/package.json +++ b/LeftOvers/package.json @@ -11,6 +11,7 @@ "dependencies": { "@expo/webpack-config": "^19.0.0", "@types/react": "~18.2.14", + "axios": "^1.6.2", "expo": "~49.0.15", "expo-linear-gradient": "~12.3.0", "expo-splash-screen": "~0.20.5", diff --git a/LeftOvers/screens/IngredientSelection.tsx b/LeftOvers/screens/IngredientSelection.tsx index 224bf47..6236a53 100644 --- a/LeftOvers/screens/IngredientSelection.tsx +++ b/LeftOvers/screens/IngredientSelection.tsx @@ -1,72 +1,39 @@ import React, { useEffect, useState } from 'react'; -import {View, StyleSheet, Text, Image, Pressable, ScrollView, ActivityIndicator} from 'react-native'; -import {SafeAreaProvider} from 'react-native-safe-area-context'; +import { View, StyleSheet, Text, Image, Pressable, ActivityIndicator, FlatList } from 'react-native'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; import TopBar from '../components/TopBar'; -import {Searchbar} from 'react-native-paper'; +import { Searchbar } from 'react-native-paper'; import FoodElementText from '../components/FoodElementText'; import CustomButton from '../components/CustomButton'; import plus from '../assets/images/plus.png'; import moins from '../assets/images/minus.png'; -import meat from '../assets/images/meat_icon.png'; -import vegetable from '../assets/images/vegetable_icon.png'; -import fruit from '../assets/images/fruit_icon.png'; -import Ingredient from '../Models/Ingredient' - +import Ingredient from '../Models/Ingredient'; +import IngredientService from '../Services/Ingredients/IngredientsServices'; export default function IngredientSelection(props) { - const [searchValue, setSearchValue] = useState(''); - const alphabetArray: Array = ["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"] - let [isLoading, setIsLoading] = useState(true); - let [error, setError] = useState(); - let [response, setResponse] = useState(); - let [SelectedIngredient, setSelectedIngredients] = useState([]); - let instancesArray: Array = []; - - -// Pour se connecter à l'API - useEffect(() => { - fetch('http://localhost:3000/ingredients') - .then(res => res.json()) - .then( - result => { - setIsLoading(false); - setResponse(result); - }, - error => { - setIsLoading(false); - setError(error); - } - ); - }, []); - -// Pour - const getContent = () => { - - if (isLoading) { - return ; - } - - if (error) { - console.log('Erreur ici' + error); - return Ca marche Pos; - } - - if (response) { - try { - instancesArray = Ingredient.convertApiResponse(JSON.stringify(response)); - - return instancesArray.map((ingredient, index) => ( - - )); - } catch (error) { - console.error("Erreur de conversion de la réponse en instances d'Ingredient:", error); - return Erreur lors du traitement des données; - } + const alphabetArray: Array = ["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 [error, setError] = useState(); + const [response, setResponse] = useState(undefined); + const [selectedIngredients, setSelectedIngredients] = useState([]); + const ingredientService = new IngredientService(); + + const loadIngredients = async () => { + try { + const ingredients = await ingredientService.getAllIngredient(); + setResponse(ingredients); + } catch (error) { + setError(error); + } finally { + setIsLoading(false); } }; -// Ingredients disponible + useEffect(() => { + loadIngredients(); + }, []); + const AvailableItem = ({ value }: { value: Ingredient }) => ( <> @@ -79,8 +46,7 @@ export default function IngredientSelection(props) { ); -// Ingredient choisi par l'utilisateur - const ChooseItem = ({ value }: { value: { id: number; name: string } }) => ( + const ChooseItem = ({ value }: { value: Ingredient }) => ( <> @@ -92,90 +58,98 @@ export default function IngredientSelection(props) { ); - function SelectIngredient(newIngredient: Ingredient) { - const exists = SelectedIngredient.find( - (ingredient) => ingredient.id === newIngredient.id - ); + const SelectIngredient = (newIngredient: Ingredient) => { + const exists = selectedIngredients.find((ingredient) => ingredient.id === newIngredient.id); if (!exists) { - setSelectedIngredients([...SelectedIngredient, newIngredient]); - console.log(newIngredient); - console.log(SelectedIngredient); - }else{ - console.log(exists) - console.log("cheh pas ajouté") + setSelectedIngredients([...selectedIngredients, newIngredient]); } -} - -function RemoveIngredient(idIngredient: Number){ - const updatedIngredients = SelectedIngredient.filter( - (ingredient) => ingredient.id !== idIngredient - ); + }; - setSelectedIngredients(updatedIngredients); -} + const RemoveIngredient = (idIngredient: number) => { + const updatedIngredients = selectedIngredients.filter((ingredient) => ingredient.id !== idIngredient); + setSelectedIngredients(updatedIngredients); + }; + const handleLetterPress = async (letter: string) => { + try { + const ingredientsByLetter = await ingredientService.getIngredientByLetter(letter); + setResponse(ingredientsByLetter); + } catch (error) { + setError(error); + } finally { + setIsLoading(false); + } + }; return ( - - - - - - - - - - - - - - - - - setSearchValue(query)} - value={searchValue} - style={{margin: 10, - backgroundColor: '#F2F0E4', - borderWidth : 1, - borderColor: "#ACA279", - borderRadius: 15, - height: 50, - }}/> - - - - - {getContent()} - - - - - - - - Available - - - - - - - {SelectedIngredient.map((source, index) => ( - - ))} - - - - - - - - - + + + + + + {alphabetArray.map((source, index) => ( + handleLetterPress(source)}> + {source} + + ))} + + + + setSearchValue(query)} + value={searchValue} + style={{ + margin: 10, + backgroundColor: '#F2F0E4', + borderWidth: 1, + borderColor: "#ACA279", + borderRadius: 15, + height: 50, + }} /> + + + + ( + + )} + keyExtractor={(item, index) => index.toString()} + ListEmptyComponent={() => ( + isLoading ? : Erreur lors du traitement des données + )} + style={{ flex: 1 }} + /> + + + + + + + Selected + + + + + ( + + )} + keyExtractor={(item, index) => index.toString()} + style={{ flex: 1 }} + /> + + + + + + + + ); } @@ -190,7 +164,7 @@ const styles = StyleSheet.create({ padding: 20, }, element: { - backgroundColor:'#F2F0E4', + backgroundColor: '#F2F0E4', borderRadius: 30, }, horizontalAlignement: {