// Composants partagés : Header, Footer, CartDrawer, PizzaCard, Toast
const { useState, useEffect, useRef } = React;
const BADGE_LABEL = {
spicy: '🌶 Piquante',
veg: 'Végé',
nouveau: 'Nouveau',
premium: 'Premium',
supplément: '🧀 Supplément',
};
function PizzaCard({ pizza, onAdd }) {
const [added, setAdded] = useState(false);
const [showSaucePicker, setShowSaucePicker] = useState(false);
const [pickedSauces, setPickedSauces] = useState([]);
const eligible = itemHasSauce(pizza);
const supps = itemSupplements(pizza);
const toggleSauce = (sid) => {
setPickedSauces(arr => arr.includes(sid) ? arr.filter(x => x !== sid) : [...arr, sid]);
};
const handleAddDirect = () => {
if (eligible) { setShowSaucePicker(true); setPickedSauces([]); return; }
addToCart(pizza.id);
setAdded(true);
onAdd && onAdd(pizza);
setTimeout(() => setAdded(false), 1400);
};
const confirmSauces = () => {
addToCart(pizza.id, { sauceIds: pickedSauces });
setShowSaucePicker(false);
setPickedSauces([]);
setAdded(true);
onAdd && onAdd(pizza);
setTimeout(() => setAdded(false), 1400);
};
const sauceExtra = pickedSauces.reduce((s, sid) => {
const sa = SAUCES.find(x => x.id === sid);
return s + (sa ? sa.price : 0);
}, 0);
return (
{pizza.photo && (
)}
{pizza.badge && (
{BADGE_LABEL[pizza.badge] || pizza.badge}
)}
{pizza.name}
{pizza.italianName}
{formatPrice(pizza.price)}
{!pizza.photo &&
{pizza.ingredients}
}
{/* === SUPPLÉMENTS INTÉGRÉS — COULEUR VERTE === */}
{supps.length > 0 && (
🧀 Suppléments
{supps.map((s, i) => (
+ {s.label}
{formatPrice(s.price)}
))}
)}
{showSaucePicker ? (
Choisissez vos sauces
(plusieurs possibles)
{SAUCES.map(s => {
const on = pickedSauces.includes(s.id);
return (
toggleSauce(s.id)}>
{on ? '✓' : '+'}
{s.label}{s.price > 0 && +{formatPrice(s.price)} }
);
})}
{ setShowSaucePicker(false); setPickedSauces([]); }}>Annuler
Ajouter {pickedSauces.length > 0 && `— ${pickedSauces.length} sauce${pickedSauces.length > 1 ? 's' : ''}`}
{sauceExtra > 0 && ` (+${formatPrice(sauceExtra)})`}
) : (
{added ? <>✓ Ajouté> : <>+ Ajouter au panier>}
)}
);
}
function Header({ activePage, onCartOpen }) {
const [cart] = useCart();
const [navOpen, setNavOpen] = useState(false);
const count = cartCount(cart);
return (
);
}
function Footer() {
return (
);
}
function CartDrawer({ open, onClose }) {
const [cart] = useCart();
const [serviceMode, setServiceMode] = useServiceMode();
const [editingSauceUid, setEditingSauceUid] = useState(null);
const [checkoutOpen, setCheckoutOpen] = useState(false);
const [confirmed, setConfirmed] = useState(false);
const [orderInfo, setOrderInfo] = useState({ name: '', phone: '', district: '', table: '', notes: '' });
const [orderNumber, setOrderNumber] = useState(null);
useEffect(() => { if (!open) return; const handler = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', handler); return () => document.removeEventListener('keydown', handler); }, [open, onClose]);
useEffect(() => { if (open) document.body.style.overflow = 'hidden'; else document.body.style.overflow = ''; return () => { document.body.style.overflow = ''; }; }, [open]);
const subtotal = cartSubtotal(cart);
const fee = serviceFee(serviceMode);
const total = subtotal + fee;
const toggleLineSauce = (uid, sauceId) => { const line = cart.find(l => l.uid === uid); if (!line) return; const current = lineSauces(line); const next = current.includes(sauceId) ? current.filter(x => x !== sauceId) : [...current, sauceId]; setLineSauces(uid, next); };
return (
<>
Votre panier
✕
{cart.length === 0 ? (
Mamma mia !
Votre panier est vide. Ajoutez quelques bonnes choses 🍕
) : cart.map(line => {
const item = ITEMS.find(i => i.id === line.itemId);
if (!item) return null;
const sauceIds = lineSauces(line);
const unit = lineUnitPrice(line);
return (
{item.name}
{itemHasSauce(item) && (
editingSauceUid === line.uid ? (
{SAUCES.map(s => {
const on = sauceIds.includes(s.id);
return (
toggleLineSauce(line.uid, s.id)}>
{on ? '✓' : '+'}
{s.label}{s.price > 0 && +{formatPrice(s.price)} }
);
})}
setEditingSauceUid(null)}>Terminer
) : (
setEditingSauceUid(line.uid)}>
{sauceIds.length > 0 ? (
<>🥫 Sauces : {sauceIds.map(sid => (SAUCES.find(s => s.id === sid) || {}).label).filter(Boolean).join(', ')} modifier >
) : (
<>🥫 + Ajouter des sauces >
)}
)
)}
{formatPrice(unit)} × {line.qty} = {formatPrice(unit * line.qty)}
setLineQuantity(line.uid, line.qty - 1)} aria-label="Diminuer">−
{line.qty}
setLineQuantity(line.uid, line.qty + 1)} aria-label="Augmenter">+
);
})}
{cart.length > 0 && (
<>
Mode de service
{SERVICE_MODES.map(m => (
setServiceMode(m.id)}>
{m.icon}
{m.label}
{m.fee > 0 && +{formatPrice(m.fee)} }
))}
Sous-total {formatPrice(subtotal)}
{fee > 0 &&
Frais de livraison {formatPrice(fee)}
}
>
)}
Total
{formatPrice(total)}
setCheckoutOpen(true)}>
{cart.length === 0 ? 'Panier vide' : 'Passer commande'}
{checkoutOpen && (
!confirmed && setCheckoutOpen(false)}>
e.stopPropagation()}>
{confirmed ? (
✓
Grazie mille !
Votre commande est enregistrée
Numéro de commande : {orderNumber}
{serviceMode === 'livraison' && <>Livraison estimée : 30–40 min Nous vous appelons en arrivant.>}
{serviceMode === 'emporter' && <>Prête à emporter dans 15–20 min Présentez votre numéro au comptoir.>}
{serviceMode === 'sur-place' && <>Commande envoyée pour la table {orderInfo.table} . Nos équipes vous l'apportent !>}
{ localStorage.removeItem('pizzeria-ilyes-cart'); window.dispatchEvent(new CustomEvent('cart-changed')); setConfirmed(false); setOrderNumber(null); setCheckoutOpen(false); onClose(); }}>Fermer
) : (
<>
Récapitulatif de commande
setCheckoutOpen(false)}>✕
Vos articles
{cart.map(line => { const it = ITEMS.find(i => i.id === line.itemId); if (!it) return null; return ({line.qty}× {it.name}{lineSauces(line).length > 0 ? ` — sauces : ${lineSauces(line).map(sid => (SAUCES.find(x => x.id === sid) || {}).label).filter(Boolean).join(', ')}` : ''} {formatPrice(lineUnitPrice(line) * line.qty)} ); })}
Mode : {(SERVICE_MODES.find(m => m.id === serviceMode) || {}).label}
Sous-total {formatPrice(subtotal)}
{fee > 0 &&
Frais de livraison {formatPrice(fee)}
}
Total {formatPrice(total)}
{ const newOrderNumber = 'ILY-' + Math.floor(1000 + Math.random() * 9000); setOrderNumber(newOrderNumber); setConfirmed(true); const lines = []; lines.push('🍕 *NOUVELLE COMMANDE — Pizzeria ILYES*'); lines.push(''); lines.push('📋 N° : *' + newOrderNumber + '*'); lines.push(''); lines.push('🛒 *Articles :*'); cart.forEach(line => { const item = ITEMS.find(i => i.id === line.itemId); if (!item) return; const unit = lineUnitPrice(line); lines.push('• ' + item.name + ' × ' + line.qty + ' — ' + formatPrice(unit * line.qty)); const sauceIds = lineSauces(line); if (sauceIds.length > 0) { lines.push(' Sauces : ' + sauceIds.map(sid => (SAUCES.find(s => s.id === sid) || {}).label).filter(Boolean).join(', ')); } }); lines.push(''); if (serviceMode === 'sur-place') { lines.push('🍽️ *Mode : Sur place*'); lines.push('Table : *' + orderInfo.table + '*'); } else if (serviceMode === 'a-emporter') { lines.push('🥡 *Mode : À emporter*'); lines.push('Client : ' + orderInfo.name); if (orderInfo.phone) lines.push('Téléphone : ' + orderInfo.phone); } else if (serviceMode === 'livraison') { lines.push('🛵 *Mode : Livraison*'); lines.push('Client : ' + orderInfo.name); lines.push('Téléphone : ' + orderInfo.phone); lines.push('Quartier : ' + orderInfo.district); } lines.push(''); lines.push('💰 Sous-total : ' + formatPrice(subtotal)); if (fee > 0) lines.push('🛵 Livraison : ' + formatPrice(fee)); lines.push('💰 *TOTAL : ' + formatPrice(total) + '*'); if (orderInfo.notes && orderInfo.notes.trim()) { lines.push(''); lines.push('📝 Notes : ' + orderInfo.notes); } const message = encodeURIComponent(lines.join('\n')); window.open('https://wa.me/213771787473?text=' + message, '_blank'); }}>
Confirmer la commande — {formatPrice(total)}
>
)}
)}
>
);
}
function Toast({ message, show }) {
return (✓ {message}
);
}
function useToast() {
const [toast, setToast] = useState({ message: '', show: false });
const timerRef = useRef();
const showToast = (message) => { setToast({ message, show: true }); clearTimeout(timerRef.current); timerRef.current = setTimeout(() => setToast(t => ({ ...t, show: false })), 2200); };
return [toast, showToast];
}
Object.assign(window, { PizzaCard, Header, Footer, CartDrawer, Toast, useToast });