/* ==========================================================================
مطعم الرياضي - الشعلة | المنطق الرئيسي للموقع
يقرأ البيانات من 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}
${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 = `
${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();