/* ========================================================================== مطعم الرياضي - الشعلة | المنطق الرئيسي للموقع يقرأ البيانات من menu.json ولا يحتاج أي تعديل عند تغيير الأصناف ========================================================================== */ /* ---------- إعدادات قابلة للتغيير بسهولة ---------- */ // رقم الواتساب الذي سيتم إرسال الطلبات إليه (بصيغة دولية بدون + أو صفر بداية) // لتغييره: عدّل القيمة أدناه أو استخدم أول رقم من "whatsappNumbers" في menu.json let WHATSAPP_NUMBER = "9647710022125"; /* ---------- الحالة العامة ---------- */ const state = { menu: null, cart: JSON.parse(localStorage.getItem("alriyadiCart") || "{}"), // { itemId: qty } currentSection: null, }; /* ---------- عناصر DOM ---------- */ const $ = (sel) => document.querySelector(sel); const sectionsGrid = $("#sectionsGrid"); const sectionsView = $("#sectionsView"); const itemsView = $("#itemsView"); const itemsContainer = $("#itemsContainer"); const itemsTitle = $("#itemsTitle"); const backBtn = $("#backBtn"); const searchInput = $("#searchInput"); const clearSearchBtn = $("#clearSearch"); const searchResults = $("#searchResults"); const cartFab = $("#cartFab"); const cartCount = $("#cartCount"); const cartDrawer = $("#cartDrawer"); const overlay = $("#overlay"); const closeCartBtn = $("#closeCart"); const cartItemsEl = $("#cartItems"); const cartEmptyEl = $("#cartEmpty"); const cartTotalEl = $("#cartTotal"); const topBtn = $("#topBtn"); const sendOrderBtn = $("#sendOrderBtn"); const loader = $("#loader"); /* ---------- أيقونات الأقسام (SVG بدون مكتبات خارجية) ---------- */ const ICONS = { skewer: ``, eastern: ``, fish: ``, food: ``, burger: ``, breakfast: ``, drink: ``, }; /* ========================================================================== تحميل البيانات ========================================================================== */ async function loadMenu() { try { const res = await fetch("menu.json", { cache: "no-store" }); if (!res.ok) throw new Error("menu.json not found"); state.menu = await res.json(); } catch (err) { itemsContainer.innerHTML = ""; sectionsGrid.innerHTML = `

تعذّر تحميل المنيو حاليًا. تأكد من وجود ملف menu.json.

`; console.error(err); hideLoader(); return; } if (state.menu.restaurant?.whatsappNumbers?.length) { WHATSAPP_NUMBER = state.menu.restaurant.whatsappNumbers[0]; } applyRestaurantInfo(); renderSections(); hideLoader(); renderCart(); } function hideLoader() { setTimeout(() => loader.classList.add("hide"), 350); } function applyRestaurantInfo() { const r = state.menu.restaurant || {}; document.title = `${r.name || "المنيو"} | المنيو الإلكتروني`; $(".restaurant-name").innerHTML = r.name ? r.name.replace(/-/g, '-') : "المطعم"; if (r.logo) $(".logo").src = r.logo; $("#hoursText span").textContent = r.hours || ""; $("#deliveryText span").textContent = r.delivery || ""; } /* ========================================================================== عرض الأقسام ========================================================================== */ function renderSections() { sectionsGrid.innerHTML = ""; state.menu.sections.forEach((section, i) => { const card = document.createElement("button"); card.className = "section-card"; card.style.animationDelay = `${i * 0.05}s`; card.setAttribute("aria-label", `فتح قسم ${section.name}`); card.innerHTML = ` ${ICONS[section.icon] || ICONS.food} ${section.name} ${section.items.length} صنف `; card.addEventListener("click", () => openSection(section.id)); sectionsGrid.appendChild(card); }); } function openSection(sectionId) { const section = state.menu.sections.find((s) => s.id === sectionId); if (!section) return; state.currentSection = sectionId; sectionsView.hidden = true; itemsView.hidden = false; itemsTitle.textContent = section.name; itemsContainer.innerHTML = ""; const hasSubCategories = section.items.some((it) => it.subCategory); if (hasSubCategories) { const groups = {}; section.items.forEach((it) => { const key = it.subCategory || "أخرى"; groups[key] = groups[key] || []; groups[key].push(it); }); Object.entries(groups).forEach(([groupName, items]) => { const h = document.createElement("h3"); h.className = "subcat-title"; h.textContent = groupName; itemsContainer.appendChild(h); itemsContainer.appendChild(buildItemsGrid(items, section.icon)); }); } else { itemsContainer.appendChild(buildItemsGrid(section.items, section.icon)); } window.scrollTo({ top: 0, behavior: "smooth" }); } function closeSection() { itemsView.hidden = true; sectionsView.hidden = false; state.currentSection = null; } /* ========================================================================== بناء بطاقات الأصناف ========================================================================== */ function buildItemsGrid(items, sectionIcon) { const grid = document.createElement("div"); grid.className = "items-grid"; items.forEach((item, i) => { grid.appendChild(buildItemCard(item, i, sectionIcon)); }); return grid; } function fallbackImageFor() { return "images/item-placeholder.svg"; } function buildItemCard(item, i = 0, sectionIcon) { const card = document.createElement("div"); card.className = "item-card"; card.dataset.itemId = item.id; card.style.animationDelay = `${Math.min(i * 0.04, 0.4)}s`; const qty = state.cart[item.id] || 0; if (qty > 0) card.classList.add("in-cart"); card.innerHTML = `
${item.name}

${item.name}

${formatPrice(item.price)}
${qty}
`; card.querySelector(".plus").addEventListener("click", () => changeQty(item.id, 1)); card.querySelector(".minus").addEventListener("click", () => changeQty(item.id, -1)); return card; } function findItemById(itemId) { for (const section of state.menu.sections) { const found = section.items.find((it) => it.id === itemId); if (found) return found; } return null; } function formatPrice(n) { return n.toLocaleString("en-US"); } /* ========================================================================== إدارة الكمية / السلة ========================================================================== */ function changeQty(itemId, delta) { const current = state.cart[itemId] || 0; let next = current + delta; if (next < 0) next = 0; // منع القيم السالبة if (next === 0) { delete state.cart[itemId]; } else { state.cart[itemId] = next; } saveCart(); syncQuantityUI(itemId, next); renderCart(); if (delta > 0) showToast(`أُضيف: ${findItemById(itemId)?.name || ""}`); } function setQty(itemId, qty) { qty = Math.max(0, qty); if (qty === 0) delete state.cart[itemId]; else state.cart[itemId] = qty; saveCart(); syncQuantityUI(itemId, qty); renderCart(); } function syncQuantityUI(itemId, qty) { document.querySelectorAll(`[data-item-id="${itemId}"]`).forEach((card) => { const valueEl = card.querySelector(".qty-value"); if (valueEl) valueEl.textContent = qty; card.classList.toggle("in-cart", qty > 0); }); } function saveCart() { localStorage.setItem("alriyadiCart", JSON.stringify(state.cart)); } function clearCart() { state.cart = {}; saveCart(); document.querySelectorAll(".item-card.in-cart").forEach((card) => { card.classList.remove("in-cart"); const valueEl = card.querySelector(".qty-value"); if (valueEl) valueEl.textContent = "0"; }); renderCart(); } function cartCountTotal() { return Object.values(state.cart).reduce((sum, q) => sum + q, 0); } function cartPriceTotal() { return Object.entries(state.cart).reduce((sum, [id, qty]) => { const item = findItemById(id); return sum + (item ? item.price * qty : 0); }, 0); } function renderCart() { const count = cartCountTotal(); cartCount.hidden = count === 0; cartCount.textContent = count; const entries = Object.entries(state.cart); cartItemsEl.innerHTML = ""; if (entries.length === 0) { cartEmptyEl.hidden = false; } else { cartEmptyEl.hidden = true; entries.forEach(([id, qty]) => { const item = findItemById(id); if (!item) return; const row = document.createElement("div"); row.className = "cart-item"; row.innerHTML = `

${item.name}

${formatPrice(item.price)} د.ع × ${qty} = ${formatPrice(item.price * qty)} د.ع
${qty}
`; row.querySelector(".plus").addEventListener("click", () => changeQty(id, 1)); row.querySelector(".minus").addEventListener("click", () => changeQty(id, -1)); cartItemsEl.appendChild(row); }); } cartTotalEl.textContent = `${formatPrice(cartPriceTotal())} د.ع`; sendOrderBtn.disabled = entries.length === 0; } /* ---------- فتح / إغلاق السلة ---------- */ function openCart() { cartDrawer.classList.add("open"); cartDrawer.setAttribute("aria-hidden", "false"); overlay.hidden = false; requestAnimationFrame(() => overlay.classList.add("show")); document.body.style.overflow = "hidden"; } function closeCart() { cartDrawer.classList.remove("open"); cartDrawer.setAttribute("aria-hidden", "true"); overlay.classList.remove("show"); setTimeout(() => (overlay.hidden = true), 300); document.body.style.overflow = ""; } cartFab.addEventListener("click", openCart); closeCartBtn.addEventListener("click", closeCart); overlay.addEventListener("click", closeCart); /* ========================================================================== البحث الفوري ========================================================================== */ function allItemsFlat() { return state.menu.sections.flatMap((s) => s.items.map((it) => ({ ...it, sectionName: s.name, sectionId: s.id, sectionIcon: s.icon }))); } function highlight(text, query) { const idx = text.toLowerCase().indexOf(query.toLowerCase()); if (idx === -1) return text; return ( text.slice(0, idx) + `${text.slice(idx, idx + query.length)}` + text.slice(idx + query.length) ); } function runSearch(query) { query = query.trim(); clearSearchBtn.hidden = query.length === 0; if (!query) { searchResults.hidden = true; searchResults.innerHTML = ""; return; } const matches = allItemsFlat().filter((it) => it.name.toLowerCase().includes(query.toLowerCase())); searchResults.hidden = false; if (matches.length === 0) { searchResults.innerHTML = `

لا توجد نتائج مطابقة لـ "${query}"

`; return; } searchResults.innerHTML = ""; matches.slice(0, 30).forEach((item) => { const qty = state.cart[item.id] || 0; const row = document.createElement("div"); row.className = "item-card"; row.style.margin = "6px 10px"; row.dataset.itemId = item.id; if (qty > 0) row.classList.add("in-cart"); row.innerHTML = `
${item.name}

${highlight(item.name, query)}

${formatPrice(item.price)}
${item.sectionName}
${qty}
`; row.querySelector(".plus").addEventListener("click", () => changeQty(item.id, 1)); row.querySelector(".minus").addEventListener("click", () => changeQty(item.id, -1)); searchResults.appendChild(row); }); } searchInput.addEventListener("input", (e) => runSearch(e.target.value)); clearSearchBtn.addEventListener("click", () => { searchInput.value = ""; runSearch(""); searchInput.focus(); }); /* ========================================================================== إرسال الطلب عبر واتساب ========================================================================== */ sendOrderBtn.addEventListener("click", () => { const entries = Object.entries(state.cart); if (entries.length === 0) return; const name = $("#customerName").value.trim(); const address = $("#customerAddress").value.trim(); const notes = $("#customerNotes").value.trim(); if (!name || !address) { showToast("الرجاء إدخال الاسم والعنوان قبل الإرسال"); if (!name) $("#customerName").focus(); else $("#customerAddress").focus(); return; } const restaurantName = state.menu.restaurant?.name || "المطعم"; let msg = `*طلب جديد من ${restaurantName}*\n\n`; entries.forEach(([id, qty]) => { const item = findItemById(id); if (!item) return; msg += `• ${item.name} × ${qty} = ${formatPrice(item.price * qty)} د.ع\n`; }); msg += `\n*المجموع الكلي: ${formatPrice(cartPriceTotal())} د.ع*\n\n`; msg += `👤 *اسم الزبون:* ${name}\n`; msg += `📍 *العنوان:* ${address}\n`; if (notes) msg += `📝 *ملاحظات:* ${notes}\n`; const url = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(msg)}`; window.open(url, "_blank"); clearCart(); $("#customerName").value = ""; $("#customerAddress").value = ""; $("#customerNotes").value = ""; closeCart(); }); /* ========================================================================== عناصر عامة: رجوع للأقسام / زر العودة للأعلى / تنبيه ========================================================================== */ backBtn.addEventListener("click", closeSection); window.addEventListener("scroll", () => { topBtn.classList.toggle("show", window.scrollY > 400); topBtn.hidden = window.scrollY <= 400 && !topBtn.classList.contains("show"); }); topBtn.hidden = false; topBtn.addEventListener("click", () => window.scrollTo({ top: 0, behavior: "smooth" })); let toastTimer; function showToast(text) { let toast = document.querySelector(".toast"); if (!toast) { toast = document.createElement("div"); toast.className = "toast"; document.body.appendChild(toast); } toast.textContent = text; toast.classList.add("show"); clearTimeout(toastTimer); toastTimer = setTimeout(() => toast.classList.remove("show"), 1800); } /* ========================================================================== تشغيل ========================================================================== */ loadMenu();