diff --git a/src/public/borne/assets/js/page-product.js b/src/public/borne/assets/js/page-product.js new file mode 100644 index 0000000..4f78a06 --- /dev/null +++ b/src/public/borne/assets/js/page-product.js @@ -0,0 +1,126 @@ +/* + * page-product.js — Product detail screen. + * + * Reads ?id=&category= from the query string. + * For menus (type === 'menu'): shows a fixed composition note rather than + * a detailed breakdown — the school JSON does not include composition data. + * Decision: composition_libre_pour_MVP=non (fixed menu composition message). + * + * After "Ajouter au panier": + * 1. Item added to cart via state.addToCart() + * 2. Button changes to "Ajoute !" for 1 second (visual feedback) + * 3. Redirect to products.html?category= + */ + +import { findProduct } from './data.js'; +import { addToCart, formatPrice } from './state.js'; +import { refreshCartBadge } from './nav.js'; + +const params = new URLSearchParams(window.location.search); +const productId = parseInt(params.get('id'), 10); +const categorySlug = params.get('category') ?? 'menus'; + +const container = document.getElementById('product-detail'); +const errorBlock = document.getElementById('product-error'); +const backBtn = document.getElementById('back-to-products'); + +if (backBtn) { + backBtn.href = `products.html?category=${categorySlug}`; +} + +async function renderProduct() { + if (!productId) { + showError('Produit introuvable.'); + return; + } + + try { + const product = await findProduct(productId); + if (!product) { + showError('Ce produit n\'existe pas.'); + return; + } + + document.title = `Wakdo - ${product.nom}`; + + const isMenu = product.type === 'menu'; + + container.innerHTML = ` +
+ ${product.nom} +
+
+

${product.nom}

+

${formatPrice(product.prix)}

+ ${isMenu ? renderMenuComposition() : ''} + +
+ `; + + document.getElementById('add-to-cart-btn').addEventListener('click', () => { + addToCart({ + id: product.id, + type: product.type, + categorie: product.categorie ?? categorySlug, + libelle: product.nom, + prix_cents: product.prix, + quantite: 1, + image: product.image + }); + refreshCartBadge(); + + const btn = document.getElementById('add-to-cart-btn'); + btn.textContent = 'Ajoute !'; + btn.disabled = true; + + /* Redirect after brief confirmation pause */ + setTimeout(() => { + window.location.href = `products.html?category=${categorySlug}`; + }, 1000); + }); + + } catch (err) { + showError('Erreur lors du chargement du produit.'); + console.error('renderProduct error:', err); + } +} + +/** + * Returns the HTML block for the menu composition note. + * The school JSON does not contain detailed composition — this is the + * intentional simplification for MVP (composition_libre_pour_MVP=non). + */ +function renderMenuComposition() { + return ` +
+

Composition du menu

+

+ Menu compose : choix burger + accompagnement + boisson — composition fixe pour ce MVP. +

+
+ `; +} + +function showError(msg) { + if (errorBlock) { + errorBlock.hidden = false; + errorBlock.textContent = msg; + } + if (container) { + container.hidden = true; + } +} + +document.addEventListener('DOMContentLoaded', renderProduct); diff --git a/src/public/borne/assets/js/page-products.js b/src/public/borne/assets/js/page-products.js new file mode 100644 index 0000000..ba7df44 --- /dev/null +++ b/src/public/borne/assets/js/page-products.js @@ -0,0 +1,86 @@ +/* + * page-products.js — Products list screen. + * + * Reads ?category= from the query string, maps to a slug via + * CATEGORY_ID_TO_SLUG, then fetches the matching product array. + * On product card click, navigates to product.html?id=&category=. + */ + +import { getProductsByCategory, getCategoryById, CATEGORY_ID_TO_SLUG } from './data.js'; +import { formatPrice } from './state.js'; + +const params = new URLSearchParams(window.location.search); +const categoryId = parseInt(params.get('category'), 10) || 1; +const categorySlug = CATEGORY_ID_TO_SLUG[categoryId] ?? 'menus'; + +const grid = document.getElementById('products-grid'); +const heading = document.getElementById('products-heading'); +const backBtn = document.getElementById('back-to-categories'); +const errorBlock = document.getElementById('products-error'); + +/* Build back URL preserving mode query param if present */ +const modeParam = params.get('mode'); + +function buildBackURL() { + const base = 'categories.html'; + return modeParam ? `${base}?mode=${modeParam}` : base; +} + +if (backBtn) { + backBtn.href = buildBackURL(); +} + +async function renderProducts() { + try { + const [products, category] = await Promise.all([ + getProductsByCategory(categorySlug), + getCategoryById(categoryId) + ]); + + if (heading && category) { + /* Capitalize first letter of the category title */ + const title = category.title.charAt(0).toUpperCase() + category.title.slice(1); + heading.textContent = `Nos ${title}`; + document.title = `Wakdo - ${title}`; + } + + if (!products.length) { + grid.innerHTML = '

Aucun produit disponible dans cette categorie.

'; + return; + } + + grid.innerHTML = ''; + products.forEach(product => { + const card = document.createElement('a'); + card.className = 'product-card'; + card.href = `product.html?id=${product.id}&category=${categorySlug}`; + card.setAttribute('aria-label', `${product.nom} - ${formatPrice(product.prix)}`); + + card.innerHTML = ` +
+ ${product.nom} +
+
+ ${product.nom} + ${formatPrice(product.prix)} +
+ `; + grid.appendChild(card); + }); + + } catch (err) { + if (errorBlock) { + errorBlock.hidden = false; + errorBlock.textContent = 'Impossible de charger les produits. Veuillez reessayer.'; + } + console.error('renderProducts error:', err); + } +} + +document.addEventListener('DOMContentLoaded', renderProducts); diff --git a/src/public/borne/product.html b/src/public/borne/product.html new file mode 100644 index 0000000..60a44e6 --- /dev/null +++ b/src/public/borne/product.html @@ -0,0 +1,65 @@ + + + + + + + + Wakdo - Produit + + + + + + + + +
+ + + + + +
+ + +
+ +
+ + + + + diff --git a/src/public/borne/products.html b/src/public/borne/products.html new file mode 100644 index 0000000..dc586f9 --- /dev/null +++ b/src/public/borne/products.html @@ -0,0 +1,68 @@ + + + + + + + + Wakdo - Produits + + + + + + + + +
+ +
+ +

Nos produits

+ Sur place +
+ + + + +
    + +
+ +
+ + + + +