Upload files to "/"
This commit is contained in:
848
index.html
Normal file
848
index.html
Normal file
@@ -0,0 +1,848 @@
|
||||
<!doctype html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Amuri Siciliano - Ordini Online</title>
|
||||
|
||||
<!-- Tailwind CSS per lo stile -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
|
||||
<!-- Font Awesome per le icone -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
|
||||
/>
|
||||
|
||||
<style>
|
||||
/* Nascondi scrollbar per i filtri orizzontali */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
/* Animazioni Carrello */
|
||||
#cart-overlay {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
#cart-drawer {
|
||||
transition: transform 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Utility per nascondere elementi */
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Animazione bounce sottile per il tasto mobile */
|
||||
@keyframes bounce-subtle {
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(-5%);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(5%);
|
||||
}
|
||||
}
|
||||
.animate-bounce-subtle {
|
||||
animation: bounce-subtle 2s infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 font-sans text-slate-800 pb-20">
|
||||
<!-- HEADER -->
|
||||
<header class="bg-orange-600 text-white sticky top-0 z-50 shadow-md">
|
||||
<div
|
||||
class="container mx-auto px-4 py-3 flex justify-between items-center"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="bg-white text-orange-600 p-2 rounded-full w-10 h-10 flex items-center justify-center"
|
||||
>
|
||||
<i class="fas fa-lemon text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-xl font-bold leading-none">
|
||||
Amuri Siciliano
|
||||
</h1>
|
||||
<p class="text-xs text-orange-100 opacity-90">
|
||||
Produttori per Passione
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onclick="toggleCart(true)"
|
||||
class="relative p-2 hover:bg-orange-700 rounded-full transition-colors"
|
||||
>
|
||||
<i class="fas fa-shopping-cart text-2xl"></i>
|
||||
<span
|
||||
id="header-cart-count"
|
||||
class="hidden absolute -top-1 -right-1 bg-white text-orange-600 text-xs font-bold w-5 h-5 flex items-center justify-center rounded-full border-2 border-orange-600"
|
||||
>0</span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- INFO BANNER -->
|
||||
<div
|
||||
id="info-banner"
|
||||
class="border-b p-4 text-sm transition-colors bg-orange-50 border-orange-100 text-gray-700"
|
||||
>
|
||||
<!-- Contenuto generato via JS -->
|
||||
</div>
|
||||
|
||||
<!-- MAIN CONTENT -->
|
||||
<main class="container mx-auto px-4 py-6">
|
||||
<!-- Category Filter -->
|
||||
<div
|
||||
id="category-filters"
|
||||
class="flex gap-2 overflow-x-auto pb-4 mb-2 no-scrollbar"
|
||||
>
|
||||
<!-- Pulsanti generati via JS -->
|
||||
</div>
|
||||
|
||||
<!-- Product Grid -->
|
||||
<div
|
||||
id="product-grid"
|
||||
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"
|
||||
>
|
||||
<!-- Prodotti generati via JS -->
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- MOBILE FLOATING BUTTON -->
|
||||
<div
|
||||
id="mobile-cart-btn"
|
||||
class="hidden fixed bottom-6 right-6 z-40 md:hidden"
|
||||
>
|
||||
<button
|
||||
onclick="toggleCart(true)"
|
||||
class="bg-orange-600 text-white p-4 rounded-full shadow-2xl flex items-center gap-2 animate-bounce-subtle"
|
||||
>
|
||||
<i class="fas fa-shopping-cart"></i>
|
||||
<span id="mobile-total-price" class="font-bold">€ 0.00</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- CART DRAWER (MODAL) -->
|
||||
<div
|
||||
id="cart-modal"
|
||||
class="hidden relative z-50"
|
||||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<!-- Overlay -->
|
||||
<div
|
||||
id="cart-overlay"
|
||||
class="fixed inset-0 bg-black/40 backdrop-blur-sm opacity-0"
|
||||
onclick="toggleCart(false)"
|
||||
></div>
|
||||
|
||||
<!-- Drawer Panel -->
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex justify-end pointer-events-none"
|
||||
>
|
||||
<div
|
||||
id="cart-drawer"
|
||||
class="pointer-events-auto relative w-full max-w-md bg-white h-full shadow-2xl flex flex-col transform translate-x-full"
|
||||
>
|
||||
<!-- Drawer Header -->
|
||||
<div
|
||||
class="p-4 border-b border-gray-100 flex justify-between items-center bg-orange-50"
|
||||
>
|
||||
<h2
|
||||
class="font-bold text-xl flex items-center gap-2 text-gray-800"
|
||||
>
|
||||
<i class="fas fa-shopping-bag text-orange-600"></i>
|
||||
Il tuo ordine
|
||||
</h2>
|
||||
<button
|
||||
onclick="toggleCart(false)"
|
||||
class="p-2 hover:bg-white rounded-full transition-colors"
|
||||
>
|
||||
<i class="fas fa-times text-gray-500 text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Drawer Items (Scrollable) -->
|
||||
<div
|
||||
id="cart-items-container"
|
||||
class="flex-grow overflow-y-auto p-4"
|
||||
>
|
||||
<!-- Items o Messaggio Vuoto generati via JS -->
|
||||
</div>
|
||||
|
||||
<!-- Drawer Footer -->
|
||||
<div
|
||||
id="cart-footer"
|
||||
class="hidden p-4 border-t border-gray-100 bg-gray-50"
|
||||
>
|
||||
<div class="space-y-2 mb-4">
|
||||
<div class="flex justify-between text-gray-600">
|
||||
<span>Articoli</span>
|
||||
<span id="cart-total-items">0</span>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between font-bold text-xl text-gray-900 border-t border-gray-200 pt-2"
|
||||
>
|
||||
<span>Totale</span>
|
||||
<span id="cart-total-price">€ 0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="order-form-container" class="space-y-3">
|
||||
<!-- Input o Messaggio Blocco generati via JS -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JAVASCRIPT LOGIC -->
|
||||
<script>
|
||||
// --- DATA ---
|
||||
const products = [
|
||||
// Agrumi
|
||||
{
|
||||
id: 1,
|
||||
category: "Agrumi",
|
||||
name: "Arancia Navel da Tavola",
|
||||
unit: "Cassetta 8kg",
|
||||
price: 18.0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
category: "Agrumi",
|
||||
name: "Arancia Navel da Spremuta",
|
||||
unit: "Cassetta 8kg",
|
||||
price: 14.0,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
category: "Agrumi",
|
||||
name: "Arancia Navel Extra Calibro",
|
||||
unit: "Cassetta 8kg",
|
||||
price: 20.0,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
category: "Agrumi",
|
||||
name: "Arancia Sfusa",
|
||||
unit: "Al Kg",
|
||||
price: 2.5,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
category: "Agrumi",
|
||||
name: "Clementine",
|
||||
unit: "Cassetta 8kg",
|
||||
price: 20.0,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
category: "Agrumi",
|
||||
name: "Clementine (Retina)",
|
||||
unit: "Retina 2kg",
|
||||
price: 5.0,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
category: "Agrumi",
|
||||
name: "Limoni",
|
||||
unit: "Cassetta 10kg",
|
||||
price: 25.0,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
category: "Agrumi",
|
||||
name: "Limoni (Retina)",
|
||||
unit: "Retina 2kg",
|
||||
price: 5.0,
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
category: "Agrumi",
|
||||
name: "Pompelmo",
|
||||
unit: "Al Kg",
|
||||
price: 3.0,
|
||||
},
|
||||
// Frutta
|
||||
{
|
||||
id: 10,
|
||||
category: "Frutta & Altro",
|
||||
name: "Mele",
|
||||
unit: "Cassetta 6kg",
|
||||
price: 13.0,
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
category: "Frutta & Altro",
|
||||
name: "Mandorle",
|
||||
unit: "500g",
|
||||
price: 10.0,
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
category: "Frutta & Altro",
|
||||
name: "Pistacchio",
|
||||
unit: "500g",
|
||||
price: 10.0,
|
||||
},
|
||||
// Conserve
|
||||
{
|
||||
id: 13,
|
||||
category: "Conserve",
|
||||
name: "Acciughe",
|
||||
unit: "580g",
|
||||
price: 14.0,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
category: "Conserve",
|
||||
name: "Acciughe al Peperoncino",
|
||||
unit: "580g",
|
||||
price: 14.0,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
category: "Conserve",
|
||||
name: "Acciughe (Piccole)",
|
||||
unit: "160g",
|
||||
price: 5.0,
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
category: "Conserve",
|
||||
name: "Sgombro",
|
||||
unit: "720g",
|
||||
price: 15.0,
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
category: "Conserve",
|
||||
name: "Sardine sotto sale",
|
||||
unit: "850g",
|
||||
price: 12.0,
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
category: "Conserve",
|
||||
name: "Tonno",
|
||||
unit: "540g",
|
||||
price: 14.0,
|
||||
},
|
||||
// Dispensa
|
||||
{
|
||||
id: 19,
|
||||
category: "Dispensa",
|
||||
name: "Miele d'Arancia",
|
||||
unit: "500g",
|
||||
price: 10.0,
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
category: "Dispensa",
|
||||
name: "Origano",
|
||||
unit: "Conf.",
|
||||
price: 3.0,
|
||||
},
|
||||
{
|
||||
id: 21,
|
||||
category: "Dispensa",
|
||||
name: "Olio EVO (Conf. 2 Litri)",
|
||||
unit: "2 Litri",
|
||||
price: 30.0,
|
||||
},
|
||||
{
|
||||
id: 22,
|
||||
category: "Dispensa",
|
||||
name: "Olio EVO (Conf. 3 Litri)",
|
||||
unit: "3 Litri",
|
||||
price: 45.0,
|
||||
},
|
||||
{
|
||||
id: 23,
|
||||
category: "Dispensa",
|
||||
name: "Olive Condite Arrabbiata",
|
||||
unit: "500g",
|
||||
price: 6.0,
|
||||
},
|
||||
{
|
||||
id: 24,
|
||||
category: "Dispensa",
|
||||
name: "Olive In Salamoia",
|
||||
unit: "500g",
|
||||
price: 6.0,
|
||||
},
|
||||
];
|
||||
|
||||
const categories = [
|
||||
"Tutti",
|
||||
...new Set(products.map((p) => p.category)),
|
||||
];
|
||||
const timeSlots = [
|
||||
"11:00 - 11:30",
|
||||
"11:30 - 12:00",
|
||||
"12:00 - 12:30",
|
||||
"12:30 - 13:00",
|
||||
"13:00 - 13:30",
|
||||
"13:30 - 14:00",
|
||||
"14:00 - 14:30",
|
||||
"14:30 - 15:00",
|
||||
];
|
||||
|
||||
// --- STATE ---
|
||||
let cart = {}; // Object like { id: { ...product, quantity: 1 } }
|
||||
let activeCategory = "Tutti";
|
||||
let marketInfo = {
|
||||
dateString: "",
|
||||
shortDate: "",
|
||||
isBlocked: false,
|
||||
};
|
||||
|
||||
// --- LOGIC: DATE & MARKET STATUS ---
|
||||
function calculateMarketStatus() {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
const dayOfWeek = today.getDay(); // 0=Dom, 1=Lun, ..., 4=Gio
|
||||
|
||||
// Scegli un giovedì di riferimento per stabilire il ciclo bisettimanale
|
||||
const referenceThursday = new Date("2025-12-11T00:00:00Z"); // Esempio: 11 Dic 2025 è una settimana di mercato
|
||||
|
||||
// Trova il giovedì della settimana corrente o della prossima se già passato
|
||||
let currentOrNextThursday = new Date(today);
|
||||
const daysUntilThursday = (4 - dayOfWeek + 7) % 7;
|
||||
currentOrNextThursday.setDate(
|
||||
today.getDate() + daysUntilThursday,
|
||||
);
|
||||
|
||||
// Calcola la differenza in settimane dal giovedì di riferimento
|
||||
const weekDiff = Math.round(
|
||||
(currentOrNextThursday - referenceThursday) /
|
||||
(1000 * 60 * 60 * 24 * 7),
|
||||
);
|
||||
|
||||
let targetDate = currentOrNextThursday;
|
||||
// Se la differenza di settimane è dispari, il mercato è la settimana successiva
|
||||
if (weekDiff % 2 !== 0) {
|
||||
targetDate.setDate(targetDate.getDate() + 7);
|
||||
}
|
||||
|
||||
// Se la data del mercato calcolata è già passata (es. oggi è ven/sab/dom),
|
||||
// il prossimo mercato utile è tra 14 giorni.
|
||||
if (today > targetDate) {
|
||||
targetDate.setDate(targetDate.getDate() + 14);
|
||||
}
|
||||
|
||||
const options = {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
};
|
||||
let dateString = targetDate.toLocaleDateString(
|
||||
"it-IT",
|
||||
options,
|
||||
);
|
||||
dateString =
|
||||
dateString.charAt(0).toUpperCase() + dateString.slice(1);
|
||||
|
||||
const shortOptions = { day: "numeric", month: "short" };
|
||||
let shortDate = targetDate.toLocaleDateString(
|
||||
"it-IT",
|
||||
shortOptions,
|
||||
);
|
||||
|
||||
// Logica di blocco: blocca solo il mercoledì e giovedì della settimana di mercato effettiva
|
||||
const daysFromTodayToMarket =
|
||||
(targetDate - today) / (1000 * 60 * 60 * 24);
|
||||
const isMarketThisWeek = daysFromTodayToMarket < 7;
|
||||
|
||||
const isClosingDay = dayOfWeek === 3 || dayOfWeek === 4; // Mercoledì o Giovedì
|
||||
const isBlocked = isMarketThisWeek && isClosingDay;
|
||||
|
||||
return { dateString, shortDate, isBlocked };
|
||||
}
|
||||
|
||||
// --- RENDERING FUNCTIONS ---
|
||||
|
||||
function renderInfoBanner() {
|
||||
const banner = document.getElementById("info-banner");
|
||||
const { dateString, isBlocked } = marketInfo;
|
||||
|
||||
// Cambia stile se bloccato
|
||||
if (isBlocked) {
|
||||
banner.className =
|
||||
"border-b p-4 text-sm transition-colors bg-red-50 border-red-100 text-red-900";
|
||||
} else {
|
||||
banner.className =
|
||||
"border-b p-4 text-sm transition-colors bg-orange-50 border-orange-100 text-gray-700";
|
||||
}
|
||||
|
||||
const blockedBadge = isBlocked
|
||||
? `<span class="inline-flex items-center gap-1 bg-red-100 text-red-700 px-2 py-0.5 rounded text-xs font-bold uppercase border border-red-200 ml-2"><i class="fas fa-lock text-xs"></i> Ordini Chiusi</span>`
|
||||
: "";
|
||||
|
||||
const blockedMessage = isBlocked
|
||||
? `<div class="mt-2 pt-2 border-t border-red-100 text-center text-xs md:text-sm text-red-700 font-medium flex justify-center items-center gap-2">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
Gli ordini online sono chiusi il giorno prima della consegna. Ci vediamo al parcheggio!
|
||||
</div>`
|
||||
: "";
|
||||
|
||||
const iconClass = isBlocked
|
||||
? "text-red-500"
|
||||
: "text-orange-600";
|
||||
|
||||
banner.innerHTML = `
|
||||
<div class="container mx-auto flex flex-col gap-3 md:flex-row md:justify-between md:items-center">
|
||||
<div class="flex items-center gap-2 font-medium">
|
||||
<i class="fas fa-map-marker-alt ${iconClass}"></i>
|
||||
<span>Foligno, Parcheggio Stadio</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 font-medium">
|
||||
<i class="fas fa-calendar-alt ${iconClass}"></i>
|
||||
<span>${dateString} | 11:00 - 15:00</span>
|
||||
${blockedBadge}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="fas fa-phone ${iconClass}"></i>
|
||||
<a href="tel:+393272335432" class="underline decoration-orange-300">+39 327 233 5432</a>
|
||||
</div>
|
||||
</div>
|
||||
${blockedMessage}
|
||||
`;
|
||||
}
|
||||
|
||||
function renderCategories() {
|
||||
const container = document.getElementById("category-filters");
|
||||
container.innerHTML = categories
|
||||
.map((cat) => {
|
||||
const isActive = activeCategory === cat;
|
||||
const classes = isActive
|
||||
? "bg-orange-600 text-white border-orange-600"
|
||||
: "bg-white text-gray-600 border-gray-200 hover:bg-gray-50";
|
||||
return `<button onclick="setCategory('${cat}')" class="px-4 py-2 rounded-full whitespace-nowrap text-sm font-medium transition-colors border ${classes}">${cat}</button>`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderProducts() {
|
||||
const grid = document.getElementById("product-grid");
|
||||
const filtered =
|
||||
activeCategory === "Tutti"
|
||||
? products
|
||||
: products.filter((p) => p.category === activeCategory);
|
||||
|
||||
grid.innerHTML = filtered
|
||||
.map((product) => {
|
||||
const quantity = cart[product.id]?.quantity || 0;
|
||||
let buttonHtml = "";
|
||||
|
||||
if (marketInfo.isBlocked) {
|
||||
buttonHtml = `
|
||||
<button disabled class="w-full py-2 bg-gray-200 text-gray-500 rounded-lg font-medium flex items-center justify-center gap-2 cursor-not-allowed">
|
||||
<i class="fas fa-lock"></i> Non disponibile
|
||||
</button>`;
|
||||
} else if (quantity === 0) {
|
||||
buttonHtml = `
|
||||
<button onclick="updateQuantity(${product.id}, 1)" class="w-full py-2 bg-orange-600 hover:bg-orange-700 text-white rounded-lg font-medium transition-colors flex items-center justify-center gap-2">
|
||||
<i class="fas fa-plus"></i> Aggiungi
|
||||
</button>`;
|
||||
} else {
|
||||
buttonHtml = `
|
||||
<div class="flex items-center justify-between bg-white rounded-lg border border-gray-200 p-1 shadow-sm">
|
||||
<button onclick="updateQuantity(${product.id}, -1)" class="w-10 h-10 flex items-center justify-center text-orange-600 hover:bg-orange-50 rounded-md transition-colors">
|
||||
<i class="fas fa-minus"></i>
|
||||
</button>
|
||||
<span class="font-bold text-lg w-8 text-center">${quantity}</span>
|
||||
<button onclick="updateQuantity(${product.id}, 1)" class="w-10 h-10 flex items-center justify-center text-orange-600 hover:bg-orange-50 rounded-md transition-colors">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden flex flex-col h-full hover:shadow-md transition-shadow">
|
||||
<div class="p-4 flex-grow">
|
||||
<div class="flex justify-between items-start mb-1">
|
||||
<span class="text-xs font-semibold text-orange-600 uppercase tracking-wider bg-orange-50 px-2 py-0.5 rounded">
|
||||
${product.category}
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="font-bold text-gray-800 text-lg mb-1">${product.name}</h3>
|
||||
<p class="text-gray-500 text-sm mb-3">${product.unit}</p>
|
||||
<div class="font-bold text-xl text-gray-900">€ ${product.price.toFixed(2)}</div>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50 border-t border-gray-100">
|
||||
${buttonHtml}
|
||||
</div>
|
||||
</div>`;
|
||||
})
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderCart() {
|
||||
const items = Object.values(cart);
|
||||
const totalItems = items.reduce(
|
||||
(sum, item) => sum + item.quantity,
|
||||
0,
|
||||
);
|
||||
const totalPrice = items.reduce(
|
||||
(sum, item) => sum + item.price * item.quantity,
|
||||
0,
|
||||
);
|
||||
|
||||
// Update UI Counters
|
||||
const countBadge = document.getElementById("header-cart-count");
|
||||
if (totalItems > 0) {
|
||||
countBadge.innerText = totalItems;
|
||||
countBadge.classList.remove("hidden");
|
||||
document
|
||||
.getElementById("mobile-cart-btn")
|
||||
.classList.remove("hidden");
|
||||
document.getElementById("mobile-total-price").innerText =
|
||||
`€ ${totalPrice.toFixed(2)}`;
|
||||
document
|
||||
.getElementById("cart-footer")
|
||||
.classList.remove("hidden");
|
||||
} else {
|
||||
countBadge.classList.add("hidden");
|
||||
document
|
||||
.getElementById("mobile-cart-btn")
|
||||
.classList.add("hidden");
|
||||
document
|
||||
.getElementById("cart-footer")
|
||||
.classList.add("hidden");
|
||||
}
|
||||
|
||||
document.getElementById("cart-total-items").innerText =
|
||||
totalItems;
|
||||
document.getElementById("cart-total-price").innerText =
|
||||
`€ ${totalPrice.toFixed(2)}`;
|
||||
|
||||
// Render Items List
|
||||
const container = document.getElementById(
|
||||
"cart-items-container",
|
||||
);
|
||||
|
||||
if (items.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="h-full flex flex-col items-center justify-center text-gray-400 space-y-4">
|
||||
<i class="fas fa-shopping-bag text-6xl opacity-20"></i>
|
||||
<p>Il carrello è vuoto</p>
|
||||
<button onclick="toggleCart(false)" class="text-orange-600 font-medium hover:underline">
|
||||
Torna al listino
|
||||
</button>
|
||||
</div>`;
|
||||
} else {
|
||||
container.innerHTML =
|
||||
`<div class="space-y-4">` +
|
||||
items
|
||||
.map(
|
||||
(item) => `
|
||||
<div class="flex justify-between items-center bg-white border border-gray-100 p-3 rounded-lg shadow-sm">
|
||||
<div class="flex-grow">
|
||||
<h4 class="font-medium text-gray-800">${item.name}</h4>
|
||||
<p class="text-xs text-gray-500">${item.unit}</p>
|
||||
<p class="text-orange-600 font-semibold mt-1">€ ${(item.price * item.quantity).toFixed(2)}</p>
|
||||
</div>
|
||||
${
|
||||
!marketInfo.isBlocked
|
||||
? `
|
||||
<div class="flex items-center gap-3 bg-gray-50 p-1 rounded-lg">
|
||||
<button onclick="updateQuantity(${item.id}, -1)" class="p-1 hover:bg-white rounded shadow-sm text-gray-600">
|
||||
<i class="fas fa-minus text-xs"></i>
|
||||
</button>
|
||||
<span class="font-bold w-4 text-center text-sm">${item.quantity}</span>
|
||||
<button onclick="updateQuantity(${item.id}, 1)" class="p-1 hover:bg-white rounded shadow-sm text-gray-600">
|
||||
<i class="fas fa-plus text-xs"></i>
|
||||
</button>
|
||||
</div>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`,
|
||||
)
|
||||
.join("") +
|
||||
`</div>`;
|
||||
}
|
||||
|
||||
// Render Footer Form area
|
||||
const formContainer = document.getElementById(
|
||||
"order-form-container",
|
||||
);
|
||||
if (marketInfo.isBlocked) {
|
||||
formContainer.innerHTML = `
|
||||
<div class="bg-red-50 border border-red-200 rounded-lg p-4 text-center">
|
||||
<i class="fas fa-lock mx-auto text-red-500 mb-2 block text-xl"></i>
|
||||
<h3 class="font-bold text-red-800">Ordini Chiusi</h3>
|
||||
<p class="text-sm text-red-600 mt-1">
|
||||
Non è più possibile inviare ordini per ${marketInfo.dateString}. Riprova venerdì per la prossima settimana!
|
||||
</p>
|
||||
</div>`;
|
||||
} else {
|
||||
const timeOptions = timeSlots
|
||||
.map((t) => `<option value="${t}">${t}</option>`)
|
||||
.join("");
|
||||
|
||||
formContainer.innerHTML = `
|
||||
<div class="space-y-3">
|
||||
<label class="block text-sm font-medium text-gray-700">
|
||||
Il tuo nome (per il ritiro)
|
||||
<input type="text" id="customer-name" placeholder="Mario Rossi" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-orange-500 focus:ring focus:ring-orange-200 focus:ring-opacity-50 p-2 border">
|
||||
</label>
|
||||
|
||||
<label class="block text-sm font-medium text-gray-700">
|
||||
Orario di ritiro indicativo
|
||||
<select id="pickup-time" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-orange-500 focus:ring focus:ring-orange-200 focus:ring-opacity-50 p-2 border">
|
||||
${timeOptions}
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<button onclick="sendOrder()" id="send-btn" class="w-full py-3 px-4 rounded-lg font-bold text-white flex items-center justify-center gap-2 shadow-lg transition-all bg-gray-400 cursor-not-allowed">
|
||||
<i class="fas fa-paper-plane"></i> Invia Ordine su WhatsApp
|
||||
</button>
|
||||
<p id="name-error" class="text-center text-xs text-red-500">Inserisci il nome per inviare l'ordine</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add Listener for input validation immediately after rendering
|
||||
const input = document.getElementById("customer-name");
|
||||
const btn = document.getElementById("send-btn");
|
||||
const error = document.getElementById("name-error");
|
||||
|
||||
if (input) {
|
||||
input.addEventListener("input", (e) => {
|
||||
const val = e.target.value.trim();
|
||||
if (val.length > 0) {
|
||||
btn.classList.remove(
|
||||
"bg-gray-400",
|
||||
"cursor-not-allowed",
|
||||
);
|
||||
btn.classList.add(
|
||||
"bg-green-500",
|
||||
"hover:bg-green-600",
|
||||
"hover:shadow-xl",
|
||||
);
|
||||
error.classList.add("hidden");
|
||||
btn.disabled = false;
|
||||
} else {
|
||||
btn.classList.add(
|
||||
"bg-gray-400",
|
||||
"cursor-not-allowed",
|
||||
);
|
||||
btn.classList.remove(
|
||||
"bg-green-500",
|
||||
"hover:bg-green-600",
|
||||
"hover:shadow-xl",
|
||||
);
|
||||
error.classList.remove("hidden");
|
||||
btn.disabled = true;
|
||||
}
|
||||
});
|
||||
// Trigger once to set initial state
|
||||
btn.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- ACTIONS ---
|
||||
|
||||
function setCategory(cat) {
|
||||
activeCategory = cat;
|
||||
renderCategories();
|
||||
renderProducts();
|
||||
}
|
||||
|
||||
function updateQuantity(id, delta) {
|
||||
if (marketInfo.isBlocked) return;
|
||||
|
||||
const product = products.find((p) => p.id === id);
|
||||
if (!cart[id]) {
|
||||
if (delta > 0) cart[id] = { ...product, quantity: 0 };
|
||||
else return;
|
||||
}
|
||||
|
||||
cart[id].quantity += delta;
|
||||
|
||||
if (cart[id].quantity <= 0) {
|
||||
delete cart[id];
|
||||
}
|
||||
|
||||
renderProducts(); // Refresh buttons in grid
|
||||
renderCart(); // Refresh drawer content
|
||||
}
|
||||
|
||||
function toggleCart(show) {
|
||||
const modal = document.getElementById("cart-modal");
|
||||
const overlay = document.getElementById("cart-overlay");
|
||||
const drawer = document.getElementById("cart-drawer");
|
||||
|
||||
if (show) {
|
||||
modal.classList.remove("hidden");
|
||||
// Small timeout to allow removing 'hidden' to render before animating opacity
|
||||
setTimeout(() => {
|
||||
overlay.classList.remove("opacity-0");
|
||||
drawer.classList.remove("translate-x-full");
|
||||
}, 10);
|
||||
} else {
|
||||
overlay.classList.add("opacity-0");
|
||||
drawer.classList.add("translate-x-full");
|
||||
setTimeout(() => {
|
||||
modal.classList.add("hidden");
|
||||
}, 300); // Wait for transition
|
||||
}
|
||||
}
|
||||
|
||||
function sendOrder() {
|
||||
const nameInput = document.getElementById("customer-name");
|
||||
const timeSelect = document.getElementById("pickup-time");
|
||||
const customerName = nameInput ? nameInput.value.trim() : "";
|
||||
const pickupTime = timeSelect ? timeSelect.value : "";
|
||||
|
||||
if (!customerName) return;
|
||||
|
||||
const items = Object.values(cart);
|
||||
const totalPrice = items.reduce(
|
||||
(sum, item) => sum + item.price * item.quantity,
|
||||
0,
|
||||
);
|
||||
|
||||
// Nuovo formato richiesto
|
||||
let message = `Ciao Amuri Siciliano!\n`;
|
||||
message += `Vorrei ordinare per Foligno (${marketInfo.shortDate}):\n\n`;
|
||||
|
||||
items.forEach((item) => {
|
||||
message += `- ${item.quantity}x ${item.name} (${item.unit}) - €${(item.price * item.quantity).toFixed(2)}\n`;
|
||||
});
|
||||
|
||||
message += `\nTotale: €${totalPrice.toFixed(2)}\n\n`;
|
||||
message += `Nome: ${customerName}\n`;
|
||||
message += `Orario indicativo: ${pickupTime}\n\n`;
|
||||
message += `Grazie!`;
|
||||
|
||||
const encodedMessage = encodeURIComponent(message);
|
||||
window.open(
|
||||
`https://wa.me/393272335432?text=${encodedMessage}`,
|
||||
"_blank",
|
||||
);
|
||||
}
|
||||
|
||||
// --- INIT ---
|
||||
window.onload = function () {
|
||||
marketInfo = calculateMarketStatus();
|
||||
renderInfoBanner();
|
||||
renderCategories();
|
||||
renderProducts();
|
||||
renderCart();
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user