:: Enseignements :: ESIPE :: E3INFO :: 2024-2025 :: Programmation Web avec JavaScript ::
[LOGO]

TP noté d'Application Web - session 2


Le but de ce TP est de réaliser une application permettant d'acheter des articles informatique en simulant un "Shopping Cart".

Vous devez créer vos fichiers dans le répertoire EXAM qui est un sous répertoire de votre répertoire home dans l'environnement de TP noté. Seuls les fichiers créés dans ce répertoire seront sauvegarder. Donc si vous ne créez pas les fichiers dans le répertoire EXAM mais dans un autre répertoire, ils ne seront pas sauvegardés, donc pas corrigés.
Comme environnement coupe les communications TCP vers l'extérieur,

Il est important de faire attention à la qualité du code que vous allez rendre. Avoir un code qui semble marcher, mais qui n'est pas maintenable, pas compréhensible ou qui contient du code mort (qui ne sert à rien) sera fortement pénalisé.

Voilà une idée graphique de l'application que l'on veut réaliser

Le but de l'application est de visualiser des produits existants (ceux-ci sont définis par le serveur). Puis de permettre à l'utilisateur d'ajouter des produits à un panier (il est possible de prendre plusieurs articles d'un même produit, on indique pour cela une quantité). Enfin, si le panier n'est pas vide, il est possible d'acheter (avec une requète au serveur) les produits du panier.
Graphiquement, l'application est composé de 3 zones. La zone des produits qui contient le titre "Product" ainsi qu'une liste des produits. La zone panier qui le titre "Cart" suivi du prix du panier, puis les articles du panier. Et enfin, une zone achat, avec le titre "Buy" qui possède un bouton "Buy" qui permet d'acheter les articles du panier.

Et voilà l'arbre DOM que l'on souhaite obtenir.

Exercice 1 - Cart

Dans un premier temps, récupérer un tar.gz le contient la commande esbuild et les bibliothèques react et react-dom.
Décompresser l'archive (tar zxvf cart-node-modules.tgz) cart-node_modules.tgz dans le répertoire EXAM.
Rappel, pour transformer le fichier JSX en JS, on utilise la commande
        ./node_modules/.bin/esbuild cart.jsx --bundle --outfile=cart.js
    

L'API REST du serveur est définie comme ceci:
  • Obtenir tous les produits: GET /api/product
    Cet appel renvoi l'ensemble des produits au format JSON.
    Vous pouvez tester en copiant dans votre navigateur http://localhost:8080/api/product.
  • Acheter les articles d'un panier: POST /api/buy
    Le JSON à envoyer doit être un objet qui à chaque id de produit indique la quantité correspondante. Par exemple, si on achète deux keyboard (id = "14") et trois headphones (id = "10"), on doit envoyer l'objet suivant
                {
                  "14": 2,
                  "10": 3
                }
               

    Cet appel renvoi un code 200 si cela s'est bien passé.

Pour démarrer, on va utiliser le fichier cart.html suivant

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <link rel="icon" href="data:,">
        <script src="cart.js" type="text/javascript"></script>
        <style>
        /* Main App Container */
        .app {
          max-width: 800px;
          margin: 0 auto;
          padding: 20px;
          font-family: Arial, sans-serif;
          line-height: 1.6;
        }

        /* Section Headers */
        .app h3 {
          color: #333;
          border-bottom: 2px solid #ddd;
          padding-bottom: 10px;
          margin: 30px 0 20px 0;
        }

        /* Product Section */
        .product-content {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 15px;
          margin: 10px 0;
          border: 1px solid #ddd;
          border-radius: 8px;
          background-color: #f9f9f9;
        }

        .product-info h3 {
          margin: 0 0 5px 0;
          color: #333;
          border: none;
          padding: 0;
        }

        .product-info p {
          margin: 0;
          font-weight: bold;
          color: #2c5530;
          font-size: 1.1em;
        }

        /* Article Section */
        .article-content {
          display: flex;
          justify-content: space-between;
          align-items: center;
          padding: 15px;
          margin: 10px 0;
          border: 1px solid #ddd;
          border-radius: 8px;
          background-color: #f0f8ff;
        }

        .article-info {
          display: flex;
          align-items: center;
          gap: 15px;
          font-weight: 500;
        }

        /* Buy Section */
        .buy-content {
          text-align: center;
          padding: 20px;
        }

        button {
          padding: 10px 20px;
          border: none;
          border-radius: 6px;
          font-size: 14px;
          font-weight: 600;
          cursor: pointer;
          min-width: 120px;
        }

        button:disabled {
          cursor: not-allowed;
          opacity: 0.6;
          transform: none;
        }

        /* Button Color Variations */
        .btn-add-cart {
          background-color: #009e4f;
          color: white;
        }

        .btn-remove-cart {
          background-color: #ff007b;
          color: white;
        }

        .btn-quantity {
          background-color: #007bff;
          color: white;
          min-width: auto;
          padding: 5px 12px;
          font-size: 12px;
        }

        .btn-buy {
          background-color: #ff7b00;
          color: white;
          font-size: 16px;
          padding: 15px 30px;
          min-width: 200px;
        }

        /* Responsive Design */
        @media (max-width: 600px) {
          .product-content, .article-content {
            flex-direction: column;
            gap: 15px;
            text-align: center;
          }

          .article-info {
            flex-direction: column;
            gap: 10px;
          }
        }
        </style>
    </head>
    <body>
        <div id="App"></div>
    </body>
</html>

    

Et pour le fichier cart.jsx suivant

     import * as React from 'react';
     import * as ReactDOM from 'react-dom/client';

     function App() {
        return <div className="app">TODO</div>;
     }

     window.onload = () => {
        const appDOM = document.getElementById("App");

        const root = ReactDOM.createRoot(appDOM);
        root.render(<App/>);
     };

    

On utilisera de plus le serveur Java JExpress.java pour servir les fichiers cart.html et cart.js et l'API REST spécifique.

  1. Utiliser esbuild pour ré-écrire le fichier JSX en fichier JS puis lancer le serveur java --enable-preview JExpress.java dans le répertoire courant et vérifier avec un navigateur que l'application s'affiche bien à l'adresse http://localhost:8080/cart.html.
  2. A partir de maintenant, on va modifier le fichier cart.jsx pour créer notre application, et il ne faudra pas oublier après chaque modification de relancer esbuild ou alors, vous pouvez utiliser l'option --watch.
    Créer un composant graphique ProductList qui permet d'afficher les produits (product), un DIV par produit, le tout dans un grand DIV. Un produit est caractérisé par un id (id), un nom (name) et un prix (price).
    Pour trouver la structure exacte, utiliser l'image de l'arbre DOM (avec les bonnes classes).
    Pour récupérer les produits au démarrage, faite un appel asynchrone avec fetch à l'API su serveur dans un useEffect.
    Note: penser que comme vous affichez une liste de produits, il ne faut pas oublier les clés pour React.

  3. On veut maintenant s'occuper du panier.
    Dans un premier temps, ajouter pour chaque produit un bouton "Add to Cart" qui permet d'ajouter un produit au panier (Cart). Pour l'instant, lors de l'ajout du produit au panier, la quantité est toujours 1.
    Écrire le composant graphique Cart ainsi que le composant CartArticle qui permettent de visualiser les articles sélectionnés par l'utilisateur dans le panier.
    Note: pour l'instant, on ne s'occupe pas des boutons.
    Note2: pour avoir la structure exacte, comme précédemment, utiliser l'image de l'arbre DOM.

  4. Faire en sorte que le panier affiche le montant total, la somme des produits multipliés par leur quantité, en haut du panier.

  5. Ajouter un bouton "Remove From Cart" au niveau d'un article qui supprime le produit du panier (quelle que soit la quantité !).

  6. On souhaite changer le fonctionnement du bouton "Add to Cart" pour le rendre un peu plus intélligent.
    Si on appuie sur ce bouton la première fois, un article correspondant au produit et avec la quantité 1 est ajouté au panier. Si on appuie une seconde fois sur le bouton, pour le même produit, alors l'article déjà présent correspondant au produit voit sa quantité incrémentée de 1.

  7. Ajouter un niveau d'un article un bouton "+1" qui permet d'incrémenter la quatité du produit de 1.

  8. Créer le composant graphique correspondant à la section d'achat (Buy).
    Faire en sorte d'afficher sur le bouton "Buy" le prix du panier.

  9. Faire en sorte que si le panier est vide, le bouton "Buy" soit désactivé.

  10. Enfin, faite en sorte que lorsque l'on clique sur le bouton d'achat "Buy", l'application transfert le panier (au bon format !) puis si le serveur a validé l'envoie, réinitialiser/vider le panier.