Open Food Facts est une base de données collaborative en ligne qui vise à répertorier des informations détaillées sur les produits alimentaires du monde entier. Lancé en 2012, ce projet participatif permet aux utilisateurs de contribuer et d'accéder à des données variées telles que les ingrédients, les informations nutritionnelles, les labels, et même des photographies des emballages. L'objectif principal d'Open Food Facts est de promouvoir la transparence dans l'industrie alimentaire en fournissant un accès libre et gratuit à des informations détaillées sur les produits, facilitant ainsi des choix alimentaires plus informés.
L'API d'Open Food Facts offre un accès structuré à la base de données. Cette API permet aux développeurs d'intégrer facilement des informations détaillées sur les produits alimentaires dans leurs sites web.
Le sujet de ce devoir consiste à réaliser en REACT (et TypeScript) une application (one page) permettant de sélectionner, dans une liste prédéfinie de produits ceux que l'on veut utiliser pour son petit déjeuner. L'idée est de pouvoir choisir des produits en fonction de l'Éco-score de chacun d'eux. L'éco-score, tel que défini dans Open Food Facts, est une évaluation environnementale des produits alimentaires. Il vise à fournir aux consommateurs des informations sur l'impact environnemental des produits qu'ils achètent. L'éco-score prend en compte différents critères liés à la production, au transport, à l'emballage, etc. La notation de l'éco-score est généralement représentée par une lettre allant de "A" à "E".
L'API est très simple d'utilisation. Il suffit de faire une requête sur une url avec un id de produit.
https://world.openfoodfacts.org/api/v2/product/${idProduct}.json
Vous aurez remarqué que l'API consiste simplement à faire télécharger un fichier JSON. Par exemple copiez/collez l'url suivant pour accéder aux (nombreuses) données associées à un pot de Nutella.
https://world.openfoodfacts.org/api/v2/product/3017620420702.json
Pour le devoir vous aurez simplement besoin d'accéder à quelques informations
//on considère qu'après une requête fetch faite sur l'ID 3017620420702, le JSON est stocké dans la variable productInfo
//Nom du produit
productInfo.product.product_name; //"Nutella"
// Nom de la marque
productInfo.product.brands; //"Ferrero,Nutella"
//Catégorie du produit
productInfo.product.categories; //"Breakfasts, Spreads, Sweet spreads ..."
// Éco-score
productInfo.product.ecoscore_grade; //"d"
// Url de l'image au format miniature
productInfo.product.image_front_small_url // "https://images.openfoodfacts.org/images/products/301/762/042/0702/front_en.127.200.jpg"
Pour le devoir vous utiliserez les id suivants :
const productIds = ['3502110005663', '3017620420702', '3228857001231', '3451790988677', '3229820129488', '3664346305860', '4006040000563'];
Si jamais le jour du devoir l'API n'est plus disponible pour une raison ou une autre, veuillez créer un fichier JSON vous même et copiez-y les données en annexe présentes à la fin du sujet.
Au chargement de la page :
Les fonctionalités attendues :
À l'exception de la couleur de la bordure des produits, ne perdez pas de temps sur la partie CSS. Si votre rendu ne ressemble pas à celui de la vidéo cela n'a aucune importance.
Ce devoir se présente sous la forme d'un projet disponible ici. Désarchivez-le, faites
npm install
puis faites
npm start
Nous vous donnons toute l'architecture du projet. Plusieurs morceaux de composants sont déjà codés. L'idée de ce devoir est, pour chaque question, de vous faire compléter puis tester un composant.
Chaque composant est testable de manière indépendante. Dans le fichier App.tsx, il faudra décommenter les composants tests (que je vous ai préparés) permettant de tester vos propres composants.
Pour répondre aux diverses questions, vous aurez peut-être besoin de relire la documentation du cours :
Dans models/product.models.tsx, tous les types de l'interface ProductModel sont mis à any. Affectez le type adéquat à chaque attribut.
Testez en décommentant la ligne <TestQuestion1/>
vous devriez voir dans la console :
Dans models/filters.type.ts, complétez le type ProductFilters composé d'un attribut color et un attribut sort (permettant de savoir si on veut un tri par marque (byBrand) ou par écoScore (byScore). À vous de trouver les bons types.
Décommenter <TestQuestion2/> vous deveriez voir dans la console :
Dans services/products.service.ts, complétez le code de
static async getProducts(ids: string[]): Promise
Cette méthode (statique et asynchrone) prend un tableau d'identifiants de produits en entrée (type string) et retourne une promesse qui, une fois résolue, fournira un tableau de modèles de produits (type ProductModel[]).
C'est donc ici qu'il faut faire autant de fetch que de produits passés en paramètres. Le code contient déjà un Promise.all pour faire le return (la ligne juste après) du tableau de produits (de type ProductModel[]) une fois seulement que tous les fetch ont abouti. Vous devez donc dans cette question
Dans cette question, il faut pouvoir créer un composant product comme sur le screen-shot ci-dessous. Allez dans components/product.tsx, complétez le code de la fonction const Product = ({ clicked, item, color }: ProductProps) => ()
Le composant Product attend trois props :
Décommenter <TestQuestion4/>. Il intègre deux composants product. Vous devriez voir dans la page les deux composants et dans la console deux affichages correspondant à deux clics réalisés (un pour chaque produit):
Dans components/Headers.tsx vous allez coder le composant permettant d'afficher un tableau indiquant, à partir d'une liste de produits, combien ont été sélectionnés par catégorie. Il faut donc compléter la corps de la fonction const Header = ({ products }: HeaderProps) => {} qui prend en props un tableau de products
Attention, il est vivement recommandé d'utiliser un useEffect pour que la vue soit rafraichie si une valeur est modifiée dans products
Cette question est la plus difficile du devoir, passez à une autre si vous coincez.
Décommenter <TestQuestion5/>. Le tableau passé en paramètre contient 5 produits dont 3 ont été sélectionnés (cf attribut selected). Vous devriez voir dans la page le tableau ci-dessous:
Dans components/Products.tsx, codez le contenu de la fonction const Products = () => {}. Ce composant ne prend pas de props en paramètre. Le tableau d'id des productsID est une constante qui vous est donnée.
Ce composant affiche tous les produits de productsID. Chaque produit est cliquable. La bordure passée par défaut est à white si on clique dessus (on ne peut pas encore choisir la couleur de la bordure).
Décommenter <TestQuestion6/>. Le tableau contient 7 produits, on voit donc les 7 composants correspondants. Sur mon screen-shot j'ai cliqué sur le nutella et le beurre. Ce qui leur a donné une bordure blanche. Si je reclique sur le beurre, la bordure blanche disparait.
Dans components/Filters.tsx, codez le contenu de const Filters = ({ changed }: FiltersProps) => {} qui affiche une liste (avec des items correspondant à des noms de couleurs) et exécute la fonction callback changed du composant père passé via la props.
Décommenter <TestQuestion7/>. Le tableau contient 6 couleurs. Sur mon screen-shot on voit que j'ai cliqué successivement sur Cyan puis White. C'est donc que la callBack de mon composant TestQuestion7 a bien été exécutée 2 fois.
Assemblez tous les composants (idéalement dans Products.tsx) pour que l'on puisse cliquer, voir les modifications dans le tableau, et changer les couleurs de bordures (donc comme sur la vidéo, sauf le tri par marque ou ecoscore)
Implémentez aux bons endroits les filtres par nom de marque ou par EcoScore
En cas de problème avec l'API, voici les 7 json dont vous avez besoin :
{
"product_name": "Tropicana Pomme origine France 1 L",
"product_brands": "Tropicana",
"categories": "Aliments et boissons à base de végétaux, Boissons, Boissons à base de végétaux, Boissons aux
fruits, Jus et nectars, Jus de fruits, Boissons sans alcool, Boissons sans sucre ajouté, Jus de pomme, Jus de
fruits pur jus, Jus de pommes pur jus",
"ecoscore_grade": "b",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/350/211/000/5663/front_fr.51.200.jpg"
}
{
"product_name": "Beurre de cacahuète Crunchy",
"product_brands": "Rapunzel",
"categories": "Aliments et boissons à base de végétaux, Aliments d'origine végétale, Légumineuses et dérivés, Produits à tartiner, Fruits à coques et dérivés, Pâtes à tartiner végétales,
Purées d'oléagineux, Beurres de légumineuses, Beurres de fruits à coques, Beurres de cacahuètes",
"ecoscore_grade": "c",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/400/604/000/0563/front_fr.76.200.jpg"
}
{
"product_name": "Muesli Raisin, Figue, Abricot",
"product_brands": "Bjorg",
"categories": "Aliments et boissons à base de végétaux, Aliments d'origine végétale, Petit-déjeuners, Céréales et pommes de terre, Céréales et dérivés, Céréales pour petit-déjeuner,
Céréales aux fruits, Mueslis, Mueslis aux fruits",
"ecoscore_grade": "b",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/322/982/012/9488/front_fr.194.200.jpg"
}
{
"product_name": "Nutella",
"product_brands": "Ferrero,Nutella",
"categories": "Breakfasts, Spreads, Sweet spreads, fr:Pâtes à tartiner, Hazelnut spreads, Chocolate spreads, Cocoa and hazelnuts spreads",
"ecoscore_grade": "d",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/301/762/042/0702/front_en.127.200.jpg"
}
{
"product_name": "Le Beurre Tendre Doux",
"product_brands": "Elle & Vire,Savencia",
"categories": "Dairies, Fats, Spreads, Spreadable fats, Animal fats, Milkfat, Dairy spread, Butters, Unsalted butters, Sweet cream butters, Butter-82-fat-unsalted-easy-to-spread,
fr:Beurres tendres",
"ecoscore_grade": "d",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/345/179/098/8677/front_en.186.200.jpg"
}
{
"product_name": "Noir Extra",
"product_brands": "Poulain",
"categories": "Snacks, Snacks sucrés, Cacao et dérivés, Chocolats, Chocolats noirs, Chocolats noirs en tablette, Chocolats noirs extra fin, Chocolat-noir-extra, Chocolats noir à croquer",
"ecoscore_grade": "d",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/366/434/630/5860/front_en.88.200.jpg"
}
{
"product_name": "Harrys brioche tressee nature au sucre perle sans additifs 500g",
"product_brands": "Harrys",
"categories": "Snacks, Snacks sucrés, Viennoiseries, Brioches, Brioches tressées, Brioches pur beurre, Brioches natures",
"ecoscore_grade": "c",
"image_front_small_url": "https://images.openfoodfacts.org/images/products/322/885/700/1231/front_fr.101.200.jpg"
}