630 lines
26 KiB
JavaScript
630 lines
26 KiB
JavaScript
/* ========================================================
|
||
غمبولة بيوتي — App Logic
|
||
⚠️ منطق الأعمال (الكتالوج / الأسعار / صيغة نص الأوردر / الأرقام الثابتة /
|
||
طريقة الحفظ في localStorage) منقول زي ما هو من النسخة السابقة بدون أي تغيير.
|
||
ممنوع تتغير القيم دي إلا لو طُلب صراحة.
|
||
======================================================== */
|
||
|
||
// =========================================================
|
||
// 1) الكتالوج (زي ما هو بالظبط — الأسماء والأحجام والأسعار)
|
||
// =========================================================
|
||
// ⚠️ سعر البخاخ هنا 365 ج (زي الكتالوج الرسمي). لو الرقم الصح فعليًا 356،
|
||
// غيّري الرقم في السطر اللي فيه "بخاخ علاج التساقط" تحت.
|
||
const CATALOG = [
|
||
{ cat: "روتين العناية بالشعر", items: [
|
||
{ name: "بخاخ علاج التساقط", sizes: [["125 مل", 365]] },
|
||
{ name: "تركيبة روبانزل", sizes: [["125 مل", 225]] },
|
||
{ name: "شامبو", sizes: [["125 مل", 110], ["200 مل", 190]] },
|
||
{ name: "بلسم", sizes: [["125 مل", 110], ["200 مل", 190]] },
|
||
{ name: "حمام كريم", sizes: [["200 مل", 175], ["350 مل", 275]] },
|
||
{ name: "سيرم", sizes: [["125 مل", 275]] },
|
||
{ name: "كريم تسريح", sizes: [["125 مل", 165], ["250 مل", 265]] },
|
||
{ name: "الروتين الكامل (باقة)", sizes: [["كل المنتجات", 1425]] },
|
||
]},
|
||
{ cat: "زيوت ومكملات فردية", items: [
|
||
{ name: "خلطة مساج", sizes: [["-", 265]] },
|
||
{ name: "جوز هند", sizes: [["125 مل", 205]] },
|
||
{ name: "نبتة شيا", sizes: [["50 مل", 140]] },
|
||
{ name: "أرجان بجوجوبا", sizes: [["-", 265]] },
|
||
{ name: "جوجوبا", sizes: [["125 مل", 185]] },
|
||
{ name: "هير سول (ماء ورد)", sizes: [["200 مل", 100]] },
|
||
]},
|
||
{ cat: "العناية بالبشرة والجسم", items: [
|
||
{ name: "كريم تفتيح الجسم", sizes: [["300 مل", 350]] },
|
||
{ name: "الشمعة المنورة", sizes: [["-", 285]] },
|
||
]},
|
||
{ cat: "الرموش والحواجب", items: [
|
||
{ name: "ماسكرا الرموش والحواجب", sizes: [["10 مل", 265]] },
|
||
]},
|
||
{ cat: "شامبو القشرة", items: [
|
||
{ name: "شامبو القشرة", sizes: [["-", 275]] },
|
||
]},
|
||
];
|
||
|
||
let customRows = [];
|
||
let customIdCounter = 0;
|
||
let orderLog = [];
|
||
|
||
// =========================================================
|
||
// 2) Navigation (Bottom Nav + Screens)
|
||
// =========================================================
|
||
const SCREEN_TITLES = {
|
||
home: 'إدارة الأوردرات',
|
||
products: 'اختيار المنتجات',
|
||
order: 'مراجعة الأوردر',
|
||
customer: 'بيانات العميل',
|
||
preview: 'إرسال الأوردر',
|
||
earnings: 'الأرباح',
|
||
};
|
||
|
||
function showScreen(name){
|
||
document.querySelectorAll('.screen').forEach(s => s.classList.toggle('active', s.dataset.screen === name));
|
||
document.querySelectorAll('.nav-btn[data-screen-btn]').forEach(b => {
|
||
b.classList.toggle('active', b.dataset.screenBtn === name);
|
||
});
|
||
document.getElementById('headerSubtitle').textContent = SCREEN_TITLES[name] || '';
|
||
document.getElementById('app').scrollTop = 0;
|
||
window.scrollTo(0,0);
|
||
updateStickyBar();
|
||
if(name === 'earnings') renderCounter();
|
||
// ملحوظة: render() بيتنادى من كل الـ inputs عند أي تغيير، وبيحدّث
|
||
// الداشبورد ونص المعاينة أوتوماتيك، فمش محتاجين ننادي حاجة تانية هنا
|
||
// (تجنّبًا لأي استدعاء متبادل بين الدوال).
|
||
render();
|
||
}
|
||
|
||
function initNav(){
|
||
document.querySelectorAll('[data-screen-btn]').forEach(btn => {
|
||
btn.addEventListener('click', () => showScreen(btn.dataset.screenBtn));
|
||
});
|
||
document.querySelectorAll('[data-goto]').forEach(btn => {
|
||
btn.addEventListener('click', () => showScreen(btn.dataset.goto));
|
||
});
|
||
}
|
||
|
||
// =========================================================
|
||
// 3) بناء قايمة المنتجات (Accordion + Cards)
|
||
// =========================================================
|
||
function buildCategories(){
|
||
const container = document.getElementById('categoriesContainer');
|
||
container.innerHTML = '';
|
||
CATALOG.forEach((catObj, ci) => {
|
||
const catDiv = document.createElement('div');
|
||
catDiv.className = 'cat' + (ci === 0 ? ' open' : '');
|
||
catDiv.innerHTML = `
|
||
<div class="cat-header" data-toggle-cat="${ci}">
|
||
<span class="cat-title">${catObj.cat} <span class="cat-count">${catObj.items.length}</span></span>
|
||
<span class="cat-chevron">▾</span>
|
||
</div>
|
||
<div class="cat-body"><div class="cat-body-inner" id="catBody${ci}"></div></div>
|
||
`;
|
||
container.appendChild(catDiv);
|
||
const body = catDiv.querySelector(`#catBody${ci}`);
|
||
catObj.items.forEach((item, ii) => {
|
||
const row = document.createElement('div');
|
||
row.className = 'prod-card';
|
||
row.id = `prodCard_${ci}_${ii}`;
|
||
const sizeOptions = item.sizes.map((s, si) => `<option value="${si}">${s[0]} — ${s[1]} ج</option>`).join('');
|
||
row.innerHTML = `
|
||
<div class="prod-top">
|
||
<div class="prod-name">${item.name}<span class="selected-tick">✔</span></div>
|
||
<div class="prod-line-total" id="lt_${ci}_${ii}">0 ج</div>
|
||
</div>
|
||
<div class="prod-controls">
|
||
<select class="size-select" id="size_${ci}_${ii}" data-render-on-change>
|
||
${sizeOptions}
|
||
</select>
|
||
<div class="qty-stepper">
|
||
<button type="button" data-qty-step="-1" data-qty-target="qty_${ci}_${ii}">−</button>
|
||
<span class="qty-value" id="qty_${ci}_${ii}">0</span>
|
||
<button type="button" data-qty-step="1" data-qty-target="qty_${ci}_${ii}">+</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
body.appendChild(row);
|
||
});
|
||
});
|
||
|
||
container.querySelectorAll('[data-toggle-cat]').forEach(header => {
|
||
header.addEventListener('click', () => {
|
||
header.closest('.cat').classList.toggle('open');
|
||
});
|
||
});
|
||
container.querySelectorAll('[data-render-on-change]').forEach(sel => {
|
||
sel.addEventListener('change', render);
|
||
});
|
||
container.querySelectorAll('[data-qty-step]').forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
const targetId = btn.dataset.qtyTarget;
|
||
const el = document.getElementById(targetId);
|
||
const step = Number(btn.dataset.qtyStep);
|
||
let current = Number(el.textContent) || 0;
|
||
current = Math.max(0, current + step);
|
||
el.textContent = current;
|
||
render();
|
||
});
|
||
});
|
||
}
|
||
|
||
function getQty(ci, ii){
|
||
const el = document.getElementById(`qty_${ci}_${ii}`);
|
||
return el ? (Number(el.textContent) || 0) : 0;
|
||
}
|
||
|
||
// =========================================================
|
||
// 4) منتج مخصص
|
||
// =========================================================
|
||
function addCustomRow(){
|
||
const id = customIdCounter++;
|
||
customRows.push({ id, name: '', size: '', price: 0, qty: 0 });
|
||
renderCustomRows();
|
||
}
|
||
|
||
function removeCustomRow(id){
|
||
customRows = customRows.filter(r => r.id !== id);
|
||
renderCustomRows();
|
||
render();
|
||
}
|
||
|
||
function renderCustomRows(){
|
||
const el = document.getElementById('customList');
|
||
if(customRows.length === 0){
|
||
el.innerHTML = '<div class="empty-state" style="padding:14px 0;"><span class="empty-text">مفيش منتجات مخصصة مضافة</span></div>';
|
||
return;
|
||
}
|
||
el.innerHTML = customRows.map(r => `
|
||
<div class="custom-item">
|
||
<button type="button" class="rm-x" data-rm-custom="${r.id}">✕</button>
|
||
<input type="text" placeholder="اسم المنتج" value="${r.name}" data-custom-field="name" data-custom-id="${r.id}">
|
||
<div class="custom-grid">
|
||
<input type="text" placeholder="الحجم" value="${r.size}" data-custom-field="size" data-custom-id="${r.id}">
|
||
<input type="number" placeholder="سعر" value="${r.price || ''}" min="0" data-custom-field="price" data-custom-id="${r.id}">
|
||
</div>
|
||
<div class="qty-stepper" style="align-self:flex-start;">
|
||
<button type="button" data-custom-qty-step="-1" data-custom-qty-id="${r.id}">−</button>
|
||
<span class="qty-value" data-custom-qty-value="${r.id}">${r.qty}</span>
|
||
<button type="button" data-custom-qty-step="1" data-custom-qty-id="${r.id}">+</button>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
el.querySelectorAll('[data-rm-custom]').forEach(b => {
|
||
b.addEventListener('click', () => removeCustomRow(Number(b.dataset.rmCustom)));
|
||
});
|
||
el.querySelectorAll('[data-custom-field]').forEach(inp => {
|
||
inp.addEventListener('input', () => {
|
||
const id = Number(inp.dataset.customId);
|
||
const field = inp.dataset.customField;
|
||
updateCustom(id, field, inp.value);
|
||
});
|
||
});
|
||
el.querySelectorAll('[data-custom-qty-step]').forEach(b => {
|
||
b.addEventListener('click', () => {
|
||
const id = Number(b.dataset.customQtyId);
|
||
const row = customRows.find(r => r.id === id);
|
||
if(!row) return;
|
||
row.qty = Math.max(0, (row.qty || 0) + Number(b.dataset.customQtyStep));
|
||
const span = el.querySelector(`[data-custom-qty-value="${id}"]`);
|
||
if(span) span.textContent = row.qty;
|
||
render();
|
||
});
|
||
});
|
||
}
|
||
|
||
function updateCustom(id, field, value){
|
||
const row = customRows.find(r => r.id === id);
|
||
if(!row) return;
|
||
row[field] = (field === 'price') ? Number(value) : value;
|
||
render();
|
||
}
|
||
|
||
// =========================================================
|
||
// 5) localStorage — نفس المفاتيح القديمة بالظبط
|
||
// =========================================================
|
||
function saveManagerPhone(){ try { localStorage.setItem('gamboola_manager_phone', document.getElementById('managerPhone').value); } catch(e){} }
|
||
function loadManagerPhone(){ try { const v = localStorage.getItem('gamboola_manager_phone'); if(v) document.getElementById('managerPhone').value = v; } catch(e){} }
|
||
|
||
function saveAgentName(){ try { localStorage.setItem('gamboola_agent_name', document.getElementById('agentName').value); } catch(e){} }
|
||
function loadAgentName(){ try { const v = localStorage.getItem('gamboola_agent_name'); if(v) document.getElementById('agentName').value = v; } catch(e){} }
|
||
|
||
function saveRate(){ try { localStorage.setItem('gamboola_rate', document.getElementById('rate').value); } catch(e){} }
|
||
function loadRate(){ try { const v = localStorage.getItem('gamboola_rate'); if(v) document.getElementById('rate').value = v; } catch(e){} }
|
||
|
||
function saveNotifyPhone(){ try { localStorage.setItem('gamboola_notify_phone', document.getElementById('notifyPhone').value); } catch(e){} }
|
||
function loadNotifyPhone(){ try { const v = localStorage.getItem('gamboola_notify_phone'); if(v) document.getElementById('notifyPhone').value = v; } catch(e){} }
|
||
|
||
function loadOrderLog(){
|
||
try { const v = localStorage.getItem('gamboola_order_log'); orderLog = v ? JSON.parse(v) : []; }
|
||
catch(e){ orderLog = []; }
|
||
}
|
||
function saveOrderLog(){ try { localStorage.setItem('gamboola_order_log', JSON.stringify(orderLog)); } catch(e){} }
|
||
|
||
function todayStr(){
|
||
const d = new Date();
|
||
return `${d.getDate()}/${d.getMonth()+1}/${d.getFullYear()}`;
|
||
}
|
||
|
||
// =========================================================
|
||
// 6) الحساب الرئيسي + بناء نص الأوردر (منطق الأعمال الأصلي)
|
||
// =========================================================
|
||
function collectItems(){
|
||
let items = [];
|
||
let productsTotal = 0;
|
||
|
||
CATALOG.forEach((catObj, ci) => {
|
||
catObj.items.forEach((item, ii) => {
|
||
const sizeSel = document.getElementById(`size_${ci}_${ii}`);
|
||
const qty = getQty(ci, ii);
|
||
const sizeIdx = Number(sizeSel.value);
|
||
const [sizeLabel, price] = item.sizes[sizeIdx];
|
||
const lineTotal = qty * price;
|
||
const ltEl = document.getElementById(`lt_${ci}_${ii}`);
|
||
if(ltEl) ltEl.textContent = lineTotal + ' ج';
|
||
const card = document.getElementById(`prodCard_${ci}_${ii}`);
|
||
if(card) card.classList.toggle('selected', qty > 0);
|
||
if(qty > 0){
|
||
items.push({ name: item.name, size: sizeLabel, qty, price, lineTotal });
|
||
productsTotal += lineTotal;
|
||
}
|
||
});
|
||
});
|
||
|
||
customRows.forEach(r => {
|
||
const lineTotal = (r.qty || 0) * (r.price || 0);
|
||
if(r.qty > 0 && r.name){
|
||
items.push({ name: r.name, size: r.size || '', qty: r.qty, price: r.price, lineTotal });
|
||
productsTotal += lineTotal;
|
||
}
|
||
});
|
||
|
||
return { items, productsTotal };
|
||
}
|
||
|
||
function render(){
|
||
const { items, productsTotal } = collectItems();
|
||
const shipping = Number(document.getElementById('shipping').value) || 0;
|
||
const grandTotal = productsTotal + shipping;
|
||
|
||
document.getElementById('productsTotal').textContent = productsTotal + ' ج';
|
||
document.getElementById('grandTotal').textContent = grandTotal + ' ج';
|
||
|
||
// ملخص شاشة "الأوردر"
|
||
const summaryEl = document.getElementById('orderSummaryList');
|
||
if(items.length === 0){
|
||
summaryEl.innerHTML = '<div class="empty-state"><span class="empty-icon">🛒</span><span class="empty-text">مفيش منتجات متضافة للطلب لسه</span></div>';
|
||
} else {
|
||
summaryEl.innerHTML = items.map(it => `
|
||
<div class="summary-row">
|
||
<div>
|
||
<div class="sr-name">${it.name}</div>
|
||
<div class="sr-meta">${it.size ? it.size + ' • ' : ''}الكمية ${it.qty}</div>
|
||
</div>
|
||
<div class="sr-price">${it.lineTotal} ج</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
const totalQty = items.reduce((s,it)=>s+it.qty,0);
|
||
updateStickyBar(totalQty, grandTotal);
|
||
updateNavBadge(totalQty);
|
||
|
||
// بنحدّث الداشبورد ونص الأوردر النهائي دايمًا (حسابات رخيصة)،
|
||
// من غير أي استدعاء متبادل بين الدوال عشان نتجنب أي تكرار لا نهائي.
|
||
renderHome(items, productsTotal);
|
||
buildOutputText(items, shipping, grandTotal);
|
||
|
||
return { items, productsTotal, shipping, grandTotal };
|
||
}
|
||
|
||
// ⚠️ صيغة نص الأوردر — الأرقام الثابتة (1500 / 000000) والفواصل والترتيب
|
||
// منقولين حرفيًا زي ما اتأكد عليهم. ممنوع تتغير إلا بطلب صريح.
|
||
function buildOutputText(items, shipping, grandTotal){
|
||
let productsLine = '';
|
||
if(items.length === 0){
|
||
productsLine = '(لسه مفيش منتجات مختارة)';
|
||
} else {
|
||
const parts = items.map(it => {
|
||
const qtyPart = it.qty > 1 ? `×${it.qty}` : '';
|
||
const sizePart = it.size ? ` ${it.size}` : '';
|
||
return `${it.name}${sizePart}${qtyPart} ${it.lineTotal}`;
|
||
});
|
||
parts.push(`شحن ${shipping}`);
|
||
productsLine = parts.join('+');
|
||
}
|
||
|
||
const name = document.getElementById('custName').value || '';
|
||
const phone1 = document.getElementById('phone1').value || '';
|
||
const phone2 = document.getElementById('phone2').value || '';
|
||
const address = document.getElementById('address').value || '';
|
||
const agentName = document.getElementById('agentName').value || '';
|
||
const date = document.getElementById('orderDate').value || todayStr();
|
||
|
||
const text =
|
||
`الاوردر /${productsLine}
|
||
1500
|
||
000000
|
||
${grandTotal}
|
||
000000
|
||
${name}
|
||
${phone1}
|
||
${phone2}
|
||
العنوان بالتفصيل / ${address}
|
||
${agentName} ${date}`;
|
||
|
||
document.getElementById('outputText').value = text;
|
||
}
|
||
|
||
// =========================================================
|
||
// 7) نسخ + واتساب (نفس المنطق الأصلي، مع fallback للموبايل)
|
||
// =========================================================
|
||
function copyText(){
|
||
const ta = document.getElementById('outputText');
|
||
const btn = document.getElementById('copyBtn');
|
||
const orig = btn.innerHTML;
|
||
const done = () => {
|
||
btn.innerHTML = 'تم النسخ ✓';
|
||
btn.style.background = 'linear-gradient(135deg, #4CAF7D, #3d9469)';
|
||
showToast('تم نسخ النص ✓');
|
||
setTimeout(() => { btn.innerHTML = orig; btn.style.background = ''; }, 1500);
|
||
};
|
||
if(navigator.clipboard && navigator.clipboard.writeText){
|
||
navigator.clipboard.writeText(ta.value).then(done).catch(() => fallbackCopy(ta, done));
|
||
} else {
|
||
fallbackCopy(ta, done);
|
||
}
|
||
}
|
||
function fallbackCopy(ta, done){
|
||
ta.removeAttribute('readonly');
|
||
ta.focus();
|
||
ta.select();
|
||
try { document.execCommand('copy'); done(); } catch(e){ showToast('انسخي النص يدويًا بالضغط المطول عليه'); }
|
||
ta.setAttribute('readonly', true);
|
||
}
|
||
|
||
function sendWhatsapp(){
|
||
const text = encodeURIComponent(document.getElementById('outputText').value);
|
||
const phone = document.getElementById('managerPhone').value.replace(/[^0-9]/g, '');
|
||
const url = phone ? `https://wa.me/${phone}?text=${text}` : `https://wa.me/?text=${text}`;
|
||
window.open(url, '_blank');
|
||
}
|
||
|
||
// =========================================================
|
||
// 8) عداد الأوردرات والأرباح (نفس المنطق الأصلي)
|
||
// =========================================================
|
||
function registerOrder(){
|
||
const name = document.getElementById('custName').value || '(بدون اسم)';
|
||
const grand = document.getElementById('grandTotal').textContent;
|
||
const date = document.getElementById('orderDate').value || todayStr();
|
||
orderLog.push({ name, grand, date, ts: Date.now() });
|
||
saveOrderLog();
|
||
renderCounter();
|
||
renderHome();
|
||
showToast('تم تسجيل الأوردر ✅');
|
||
}
|
||
|
||
function undoLastOrder(){
|
||
if(orderLog.length === 0) return;
|
||
if(!confirm('متأكدة تمسحي آخر أوردر مسجل؟')) return;
|
||
orderLog.pop();
|
||
saveOrderLog();
|
||
renderCounter();
|
||
renderHome();
|
||
}
|
||
|
||
function clearLog(){
|
||
if(!confirm('متأكدة تمسحي كل السجل والعدّاد يرجع صفر؟')) return;
|
||
orderLog = [];
|
||
saveOrderLog();
|
||
renderCounter();
|
||
renderHome();
|
||
}
|
||
|
||
function renderCounter(){
|
||
const rate = Number(document.getElementById('rate').value) || 0;
|
||
const count = orderLog.length;
|
||
const earned = count * rate;
|
||
|
||
document.getElementById('earnCount').textContent = count;
|
||
document.getElementById('earnRateDisplay').textContent = rate + ' ج';
|
||
document.getElementById('earnTotal').textContent = earned + ' ج';
|
||
|
||
const logEl = document.getElementById('orderLog');
|
||
if(count === 0){
|
||
logEl.innerHTML = '<div class="empty-state"><span class="empty-icon">🗒️</span><span class="empty-text">مفيش أوردرات مسجلة لسه</span></div>';
|
||
} else {
|
||
const last15 = orderLog.slice(-15).reverse();
|
||
logEl.innerHTML = last15.map((o, i) => `
|
||
<div class="tl-item">
|
||
<div class="tl-price">${o.grand}</div>
|
||
<div class="tl-title">#${count - i} — ${o.name}</div>
|
||
<div class="tl-meta">${o.date}</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
}
|
||
|
||
function notifyWhatsapp(){
|
||
const rate = Number(document.getElementById('rate').value) || 0;
|
||
const count = orderLog.length;
|
||
const earned = count * rate;
|
||
const msg = `تحديث أوردرات غمبولة 📊\nعدد الأوردرات: ${count}\nالمستحق: ${earned} جنيه`;
|
||
const text = encodeURIComponent(msg);
|
||
const phone = document.getElementById('notifyPhone').value.replace(/[^0-9]/g, '');
|
||
const url = phone ? `https://wa.me/${phone}?text=${text}` : `https://wa.me/?text=${text}`;
|
||
window.open(url, '_blank');
|
||
}
|
||
|
||
// =========================================================
|
||
// 9) واجهة إضافية: Home dashboard / Sticky bar / Badge / Toast
|
||
// =========================================================
|
||
// items/productsTotal اختياريين — لو معدّياش، بتتحسب من تاني (بدون ما تنادي render()).
|
||
function renderHome(items, productsTotal){
|
||
if(items === undefined){
|
||
const collected = collectItems();
|
||
items = collected.items;
|
||
productsTotal = collected.productsTotal;
|
||
}
|
||
const rate = Number(document.getElementById('rate').value) || 0;
|
||
document.getElementById('homeOrderCount').textContent = orderLog.length;
|
||
document.getElementById('homeEarned').textContent = (orderLog.length * rate) + ' ج';
|
||
|
||
const shipping = Number(document.getElementById('shipping').value) || 0;
|
||
document.getElementById('homeCartItems').textContent = items.reduce((s,it)=>s+it.qty,0);
|
||
document.getElementById('homeCartTotal').textContent = (items.length ? productsTotal + shipping : 0) + ' ج';
|
||
}
|
||
|
||
// totalQty/grandTotal اختياريين — لو معدّياش، بيتحسبوا من تاني.
|
||
function updateStickyBar(totalQty, grandTotal){
|
||
const bar = document.getElementById('stickyOrderBar');
|
||
const productsScreenActive = document.querySelector('.screen[data-screen="products"]').classList.contains('active');
|
||
if(!productsScreenActive){ bar.classList.remove('show'); return; }
|
||
|
||
if(totalQty === undefined){
|
||
const collected = collectItems();
|
||
totalQty = collected.items.reduce((s,it)=>s+it.qty,0);
|
||
const shipping = Number(document.getElementById('shipping').value) || 0;
|
||
grandTotal = collected.productsTotal + shipping;
|
||
}
|
||
|
||
if(!totalQty){
|
||
bar.classList.remove('show');
|
||
return;
|
||
}
|
||
document.getElementById('stickyText').textContent = `${totalQty} منتجات — ${grandTotal} ج`;
|
||
bar.classList.add('show');
|
||
}
|
||
|
||
function updateNavBadge(count){
|
||
const badge = document.getElementById('productsBadge');
|
||
if(count > 0){
|
||
badge.textContent = count;
|
||
badge.classList.remove('hidden');
|
||
} else {
|
||
badge.classList.add('hidden');
|
||
}
|
||
}
|
||
|
||
let toastTimer = null;
|
||
function showToast(msg){
|
||
const toast = document.getElementById('toast');
|
||
toast.textContent = msg;
|
||
toast.classList.add('show');
|
||
clearTimeout(toastTimer);
|
||
toastTimer = setTimeout(() => toast.classList.remove('show'), 1800);
|
||
}
|
||
|
||
function resetCurrentOrder(){
|
||
CATALOG.forEach((catObj, ci) => {
|
||
catObj.items.forEach((item, ii) => {
|
||
const qtyEl = document.getElementById(`qty_${ci}_${ii}`);
|
||
if(qtyEl) qtyEl.textContent = '0';
|
||
const sizeEl = document.getElementById(`size_${ci}_${ii}`);
|
||
if(sizeEl) sizeEl.value = '0';
|
||
});
|
||
});
|
||
customRows = [];
|
||
renderCustomRows();
|
||
document.getElementById('custName').value = '';
|
||
document.getElementById('phone1').value = '';
|
||
document.getElementById('phone2').value = '';
|
||
document.getElementById('address').value = '';
|
||
document.getElementById('orderDate').value = todayStr();
|
||
render();
|
||
renderHome();
|
||
}
|
||
|
||
// =========================================================
|
||
// 10) PWA: تسجيل Service Worker + زرار التثبيت
|
||
// =========================================================
|
||
function registerServiceWorker(){
|
||
if('serviceWorker' in navigator){
|
||
window.addEventListener('load', () => {
|
||
navigator.serviceWorker.register('sw.js').catch(() => {});
|
||
});
|
||
}
|
||
}
|
||
|
||
let deferredInstallPrompt = null;
|
||
function initInstallPrompt(){
|
||
const installBtn = document.getElementById('installBtn');
|
||
|
||
window.addEventListener('beforeinstallprompt', (e) => {
|
||
e.preventDefault();
|
||
deferredInstallPrompt = e;
|
||
installBtn.classList.add('show');
|
||
});
|
||
|
||
installBtn.addEventListener('click', async () => {
|
||
if(!deferredInstallPrompt) return;
|
||
deferredInstallPrompt.prompt();
|
||
await deferredInstallPrompt.userChoice;
|
||
deferredInstallPrompt = null;
|
||
installBtn.classList.remove('show');
|
||
});
|
||
|
||
window.addEventListener('appinstalled', () => {
|
||
installBtn.classList.remove('show');
|
||
showToast('تم تثبيت التطبيق 🎉');
|
||
});
|
||
|
||
// iOS Safari: مفيش beforeinstallprompt، فبنعرض تلميح بسيط بدل ما نضايق المستخدم
|
||
const isIos = /iphone|ipad|ipod/i.test(navigator.userAgent);
|
||
const isStandalone = window.navigator.standalone === true || window.matchMedia('(display-mode: standalone)').matches;
|
||
const dismissed = localStorage.getItem('gamboola_ios_hint_dismissed') === '1';
|
||
if(isIos && !isStandalone && !dismissed){
|
||
document.getElementById('iosHint').classList.remove('hidden');
|
||
}
|
||
document.getElementById('closeIosHint').addEventListener('click', () => {
|
||
document.getElementById('iosHint').classList.add('hidden');
|
||
try { localStorage.setItem('gamboola_ios_hint_dismissed', '1'); } catch(e){}
|
||
});
|
||
}
|
||
|
||
// =========================================================
|
||
// 11) ربط الأحداث العامة + التشغيل الأول
|
||
// =========================================================
|
||
function initFieldListeners(){
|
||
['shipping'].forEach(id => document.getElementById(id).addEventListener('input', render));
|
||
['custName','phone1','phone2','address'].forEach(id => document.getElementById(id).addEventListener('input', render));
|
||
document.getElementById('agentName').addEventListener('input', () => { saveAgentName(); render(); });
|
||
document.getElementById('orderDate').addEventListener('input', render);
|
||
document.getElementById('managerPhone').addEventListener('input', saveManagerPhone);
|
||
document.getElementById('rate').addEventListener('input', () => { saveRate(); renderCounter(); renderHome(); });
|
||
document.getElementById('notifyPhone').addEventListener('input', saveNotifyPhone);
|
||
|
||
document.getElementById('addCustomBtn').addEventListener('click', addCustomRow);
|
||
document.getElementById('copyBtn').addEventListener('click', copyText);
|
||
document.getElementById('sendWaBtn').addEventListener('click', sendWhatsapp);
|
||
document.getElementById('registerOrderBtn').addEventListener('click', registerOrder);
|
||
document.getElementById('undoOrderBtn').addEventListener('click', undoLastOrder);
|
||
document.getElementById('clearLogBtn').addEventListener('click', clearLog);
|
||
document.getElementById('notifyWaBtn').addEventListener('click', notifyWhatsapp);
|
||
document.getElementById('startNewOrderBtn').addEventListener('click', () => {
|
||
resetCurrentOrder();
|
||
showScreen('products');
|
||
});
|
||
document.getElementById('goToCustomerBtn').addEventListener('click', () => showScreen('customer'));
|
||
document.getElementById('goToPreviewBtn').addEventListener('click', () => showScreen('preview'));
|
||
}
|
||
|
||
function init(){
|
||
document.getElementById('orderDate').value = todayStr();
|
||
buildCategories();
|
||
renderCustomRows();
|
||
loadManagerPhone();
|
||
loadAgentName();
|
||
loadRate();
|
||
loadNotifyPhone();
|
||
loadOrderLog();
|
||
initFieldListeners();
|
||
initNav();
|
||
registerServiceWorker();
|
||
initInstallPrompt();
|
||
render();
|
||
renderCounter();
|
||
renderHome();
|
||
showScreen('home');
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', init);
|