Aller au contenu

Frontend e-commerce

Le frontend e-commerce est l'application principale exposée aux visiteurs et aux étudiants. C'est une Single Page Application React 18 servie par un conteneur Nginx, qui consomme exclusivement les APIs REST du backend Spring Boot. Elle joue trois rôles superposés : vitrine marchande réaliste, cible des chaos backend et frontend, et surface de jeu pour le parcours pédagogique.

Sources

frontend/src/App.jsx, frontend/src/main.jsx, frontend/src/services/api.js, frontend/src/pages/*.jsx, frontend/src/i18n/I18nContext.jsx

Stack

Composant Version / choix Rôle
React 18 (createRoot, Concurrent Mode) Rendu
React Router v6 (BrowserRouter, Routes) Navigation côté client
Vite 5 Bundling, dev server, HMR
I18nContext maison zéro dépendance Traduction FR/EN par import statique
fetch natif Appels API avec credentials: 'include'
Nginx (runtime) 1.27 Alpine Serveur statique + env-inject.sh

Le point d'entrée main.jsx monte <App> à l'intérieur d'un <I18nProvider> et d'un <React.StrictMode>. App.jsx déclare le <Router> et un AppShell qui gère la navbar, le footer, et monte <PedagogiqueOrchestrator> en dehors des <Routes> afin que l'overlay pédagogique survive à toutes les navigations.

Routes

Les routes sont déclarées dans App.jsx. Toutes les routes sauf /s/:token sont rendues à l'intérieur de l'AppShell standard (navbar + footer).

Chemin Composant Protection
/ Redirection vers /products
/products Products Public
/products/:id ProductDetail Public
/login Login Redirige vers /products si déjà connecté
/register Register Public
/cart Cart Public (panier anonyme supporté)
/checkout Checkout Exige un utilisateur connecté, sinon redirection vers /login
/order-confirmation OrderConfirmation Public (arrivée après création de commande)
/orders MyOrders Exige un utilisateur connecté
/profile Profile Exige un utilisateur connecté
/admin AdminPortal Public intentionnellement — portail de sécurité S10-S12
/s/:token PedagogiqueSucces Page standalone — sans navbar, sans footer, sans orchestrateur

Les routes dont le chemin commence par /s/ sont identifiées par la constante STANDALONE_PREFIXES et rendues sans le chrome applicatif. Le token dans l'URL sert d'authentification opaque vers la page de succès : il est non-devinable et unique par session.

État global

App.jsx gère trois états locaux qui font office d'état global :

  • user — objet { id } ou null, rempli au démarrage par getAuthStatus()
  • cart — tableau des items ajoutés localement, synchronisé avec le backend
  • loading — booléen de démarrage, le temps de résoudre la session HTTP

Quatre callbacks sont passés en props à toutes les pages qui touchent au panier : addToCart, removeFromCart, updateCartQuantity, clearCart. L'ajout au panier appelle d'abord apiAddToCart() côté API puis met à jour l'état local — une approche « optimiste » qui masque la latence réseau.

Service API (services/api.js)

Le fichier services/api.js concentre tous les appels réseau du frontend. Aucune page React ne fait de fetch direct : elles passent systématiquement par les fonctions exportées de ce module.

Base URL

export const API_BASE_URL =
  import.meta.env.VITE_API_URL || 'https://perfshop-api.perfshop.io';

VITE_API_URL est injectée au démarrage du conteneur Nginx par le script env-inject.sh (même mécanisme que VITE_LANG) : cela permet de construire l'image une seule fois et de la déployer sur plusieurs cibles (dev, prod NAS, VPS) sans rebuild.

Tokens Chaos Scripting

Le module maintient un store interne _tokens qui stocke les cinq headers HTTP nécessaires aux niveaux Chaos Scripting (X-Session-Token, X-Action-Token, X-CSRF-Token, X-Step-Token, X-Signature). Le cycle de vie est centralisé :

Fonction Rôle
_extractTokens(response) Lit les headers de réponse et met à jour _tokens
_buildCheckoutHeaders() Construit les headers à envoyer sur chaque étape du checkout
_clearTokens() Vide le store au logout
_throwScriptingError(status, err) Propage les erreurs préfixées [Chaos Scripting CODE]

Seul le tunnel checkout (submitAddresssubmitShippingsubmitPaymentcreateOrder) injecte ces headers. Les endpoints panier et catalogue restent libres — c'est une exigence fonctionnelle du Chaos Scripting : « le panier est toujours libre, seul le checkout est protégé ». Voir Chaos Scripting pour le détail.

Familles de fonctions exposées

Famille Fonctions principales
Authentification login, logout, getAuthStatus
Catalogue getProducts, getProduct, getCategories, searchProducts
Panier addToCart, getCart, updateCartItem, removeFromCart, clearCart
Checkout submitAddress, submitShipping, submitPayment, createOrder
Profil / pays getProfile, updateProfile, getCountries
Commandes verifyCheckoutAccess, getUserOrders, cancelOrder

Toutes les fonctions retournent des promesses et lancent une Error dont le message est soit une clé i18n (ex : 'api.error.loadProducts') soit une chaîne brute si l'origine est serveur. La résolution de ces clés est déléguée au hook useT().tErr() décrit plus bas.

Propagation du token pédagogique

createOrder lit localStorage.getItem('ped_student_token') et, s'il existe, l'envoie dans le header X-Student-Token. Le backend reconnaît alors la commande comme venant d'un parcours pédagogique et répond avec l'agentCode qui sera affiché sur la page de confirmation.

Pages applicatives

Les pages sont toutes des composants fonctionnels qui consomment useT() pour l'i18n et les fonctions de services/api.js pour les appels réseau.

Page Rôle principal
Home.jsx Landing marchande, redirigée vers /products par défaut
Products.jsx Liste paginée du catalogue, filtre catégorie, recherche texte
ProductDetail.jsx Fiche produit, bouton « Ajouter au panier »
SearchBar.jsx Composant de recherche, utilisé dans l'en-tête catalogue
CategorySidebar.jsx Panneau de filtrage par catégorie
Cart.jsx Panier, modification des quantités, passage au checkout
Checkout.jsx Tunnel multi-étapes : adresse, livraison, paiement, validation
OrderConfirmation.jsx Récapitulatif post-commande, affichage de l'agentCode si parcours actif
MyOrders.jsx Historique des commandes du compte connecté
Profile.jsx Édition du profil utilisateur (civilité, date de naissance, adresse)
Login.jsx Formulaire de connexion
Register.jsx Création de compte
AdminPortal.jsx Portail admin pédagogique S10-S12 — voir Portail admin

Pages du parcours pédagogique

Trois composants et un hook forment le sous-système pédagogique :

  • usePedagogiqueState.js — hook qui poll /api/chaos/student/status toutes les 15 secondes et renvoie { state, refresh }. Il accepte un skipPollingRef pour suspendre le polling pendant les animations de note culturelle.
  • PedagogiqueOrchestrator.jsx — point d'entrée monté une seule fois dans AppShell. Ne rend rien si le parcours est inactif. Navigue automatiquement vers /s/:token quand le parcours est complété, via un useEffect dépendant de state.completed. Réinitialise ses flags locaux (localTimerExpired, navigatedRef) quand state.level change — via un useEffect pour éviter toute mutation de ref dans le corps du composant (anti-pattern React 18 Concurrent Mode).
  • PedagogiqueTimer.jsx — compteur visuel persistant, reçoit timerRemaining et timerTotal du hook et notifie l'orchestrateur via onExpired.
  • PedagogiqueOverlay.jsx — fenêtre modale non-bloquante qui affiche l'énigme courante, son énoncé, son champ de réponse, les indices et les étoiles. Accepte hintsEnabled avec rétrocompatibilité !== false (les anciens payloads serveur sans ce champ restent valides).
  • pedagogique/succes/PedagogiqueSucces.jsx — page standalone de succès, chargée via la route /s/:token.

Voir Concept et architecture du parcours pédagogique pour le détail du fonctionnement.

Internationalisation

Le provider I18nContext.jsx charge statiquement les fichiers fr.json et en.json au build, et résout la langue active à partir de la variable Vite VITE_LANG (défaut fr). La langue est fixée au démarrage et ne change pas pendant la session — ce choix est aligné sur la stratégie globale PerfShop (voir Internationalisation).

Deux fonctions sont exposées par le hook useT() :

  • t(key, replacements) — traduit une clé ; le fallback est le dictionnaire français, puis la clé brute
  • tErr(msg) — résout un message d'erreur qui peut être soit une clé i18n (comme celles levées par services/api.js), soit une chaîne serveur brute. Cette fonction évite d'afficher api.error.loadProducts à l'utilisateur final quand la traduction n'est pas trouvée.

Un useEffect met à jour document.documentElement.lang à chaque changement de lang, ce qui permet aux outils d'accessibilité et au référencement de connaître la langue du document.

Diagramme de navigation

flowchart TD
  Root["/"] --> Products["/products"]
  Products --> Detail["/products/:id"]
  Detail --> Cart["/cart"]
  Products --> Cart
  Cart --> CheckoutGuard{Utilisateur<br/>connecté ?}
  CheckoutGuard -- non --> Login["/login"]
  Login -- après login --> Checkout["/checkout"]
  CheckoutGuard -- oui --> Checkout
  Checkout --> Confirm["/order-confirmation"]
  Confirm --> MyOrders["/orders"]
  Products --> Profile["/profile"]
  Login --> Register["/register"]
  Products --> AdminPortal["/admin<br/>portail S10-S12"]
  Confirm -. "si parcours<br/>complété" .-> Success["/s/:token<br/>standalone"]

Chaos Agent frontend

App.jsx importe chaos-agent.js pour ses effets de bord — ce script s'exécute immédiatement côté navigateur et installe les handlers nécessaires au Chaos Frontend (CPU burn, memory leak, DOM flood, fetch flood). Il poll /api/chaos/frontend/state toutes les 5 secondes et active ou désactive les perturbations côté client en conséquence. Voir Chaos Frontend pour le détail des comportements injectés.

Build et déploiement

Le frontend est distribué sous forme d'image Docker (docker-compose.yml → service perfshop-frontend). Le Dockerfile effectue un build Vite puis copie les assets dans Nginx. Le script env-inject.sh exécuté à l'ENTRYPOINT remplace les marqueurs __VITE_API_URL__ et __VITE_LANG__ dans les fichiers JavaScript compilés — cela permet de publier une image générique et de la configurer à l'exécution.

Pour le build local, voir Build frontend.