/* ========================================================================= * cart.js — количка, checkout и потвърждение (клиентски рендер, фаза 1) * Фаза 2: тези страници стават server-rendered от Spring MVC (session cart), * стъпките на checkout — отделни partials (както cart step1/2/3 в salex). * ========================================================================= */ (function () { 'use strict'; var esc = window.ACM.esc, fmt = window.ACM.fmtPrice, DEMO = window.ACM.demo; var Cart = window.ACM.cart, find = window.ACM.findProduct; function el(id) { return document.getElementById(id); } function icon(paths, size, sw) { return ''; } var IC = { minus: '', plus: '', trash: '', package: '', arrowRight: '', arrowLeft: '', info: '', warn: '', ban: '', check: '' }; function lines() { return Cart.items().map(function (i) { var p = find(i.productId); if (!p) return null; var isPack = p.package.unitLabel === 'пакет'; return { product: p, qty: i.qty, isPack: isPack, unit: isPack ? 'бр.' : 'каш.', lineTotal: p.price.perBox * i.qty }; }).filter(Boolean); } function thumb(p, size) { var inner = p.image ? '' : '' + icon(IC.package, Math.round(size * 0.4), 1.25) + ''; return '' + inner + ''; } function stepperHTML(id, qty, unit) { return '
' + '' + '
' + '' + '' + esc(unit) + '' + '
' + '' + '
'; } function wireSteppers(root) { Array.prototype.forEach.call(root.querySelectorAll('[data-stepper]'), function (st) { var id = st.getAttribute('data-stepper'); var input = st.querySelector('input'); function val() { var v = parseInt(input.value, 10); return isNaN(v) ? 1 : Math.min(9999, Math.max(1, v)); } st.querySelector('[data-minus]').addEventListener('click', function () { Cart.setQty(id, val() - 1); }); st.querySelector('[data-plus]').addEventListener('click', function () { Cart.setQty(id, val() + 1); }); input.addEventListener('change', function () { Cart.setQty(id, val()); }); }); } function wireRemoves(root) { Array.prototype.forEach.call(root.querySelectorAll('[data-remove]'), function (b) { b.addEventListener('click', function () { var id = b.getAttribute('data-remove'); var snapshot = Cart.items(); Cart.remove(id); window.ACM.showToast('Продуктът е премахнат', { actionLabel: 'Върни', onAction: function () { Cart.restore(snapshot); } }); }); }); } /* ---------------------- Кредитен статус (както в оригинала) ------------- */ function creditBanner(state) { var map = { info: { ic: IC.info, box: 'bg-green-tint text-ink', icc: 'text-green-deep', text: 'Кредитни условия: отложено плащане по договорени падежи.' }, warning: { ic: IC.warn, box: 'bg-warn-bg text-warn-text', icc: 'text-warn-text', text: 'Наближавате кредитния си лимит. При въпроси се свържете с вашия търговски представител.' }, blocked: { ic: IC.ban, box: 'bg-danger-bg text-danger', icc: 'text-danger', text: 'Поръчката надвишава кредитния ви лимит. Свържете се с АСМ за съдействие.' } }; var c = map[state]; return '
' + '' + icon(c.ic, 20) + '' + '

' + c.text + '

'; } /* ---------------------- Резюме на поръчката ----------------------------- */ function summaryHTML(deliveryMethod, ctaHTML) { var ls = lines(); var subtotal = ls.reduce(function (s, l) { return s + l.lineTotal; }, 0); var delivery = deliveryMethod === null ? 0 : window.ACM.deliveryCost(deliveryMethod, subtotal); var m = deliveryMethod === null ? null : DEMO.deliveryMethods.find(function (d) { return d.method === deliveryMethod; }); var deliveryDisplay = deliveryMethod === null ? '—' : (m && m.cost === null) ? 'по тарифа' : delivery === 0 ? 'Безплатно' : fmt(delivery); var vat = (subtotal + delivery) * DEMO.vat; var total = subtotal + delivery + vat; var credit = window.ACM.creditState(subtotal); function row(label, value, muted) { return '
' + '' + label + '' + '' + value + '
'; } return ''; } /* ======================== Страница: Количка ============================ */ function renderCartPage() { var ls = lines(); el('cart-empty').hidden = ls.length > 0; el('cart-full').hidden = ls.length === 0; if (!ls.length) return; el('cart-rows').innerHTML = ls.map(function (l) { var p = l.product; return '' + '
' + thumb(p, 56) + '
' + esc(p.name) + '' + '

Арт. № ' + esc(p.artNumber) + '

' + '' + fmt(p.price.perBox) + '' + '' + stepperHTML(p.id, l.qty, l.unit) + '' + '' + fmt(l.lineTotal) + '' + '' + ''; }).join(''); el('cart-cards').innerHTML = ls.map(function (l) { var p = l.product; return '
' + '
' + thumb(p, 56) + '
' + esc(p.name) + '' + '

Арт. № ' + esc(p.artNumber) + '

' + '

' + fmt(p.price.perBox) + '

' + '
' + '
' + stepperHTML(p.id, l.qty, l.unit) + '' + fmt(l.lineTotal) + '
'; }).join(''); el('cart-summary').innerHTML = summaryHTML(null, 'Продължи към доставка' + icon(IC.arrowRight, 20) + ''); wireSteppers(document); wireRemoves(document); } /* ======================== Страница: Checkout =========================== */ var coState = { step: 2, delivery: 'pickup', warehouse: 'Монтана', addressId: 'addr-1', payment: 'deferred' }; function radioCard(name, value, checked, title, note) { return ''; } function renderCheckoutStep2() { var html = ''; html += '
' + '' + icon(IC.check, 20) + '' + '

Всички продукти са налични

'; html += '
' + '

Начин на доставка

' + '
' + DEMO.deliveryMethods.map(function (m) { return radioCard('co-delivery', m.method, coState.delivery === m.method, m.label, m.note); }).join('') + '
'; if (coState.delivery === 'pickup') { html += '
' + '

Склад за изпълнение

' + '
' + DEMO.warehouses.map(function (w) { var sel = coState.warehouse === w.name; return ''; }).join('') + '
'; } else { html += '
' + '

Адрес за доставка

' + '
' + DEMO.addresses.map(function (a) { return radioCard('co-address', a.id, coState.addressId === a.id, a.label, a.isDefault ? 'По подразбиране' : ''); }).join('') + '
' + '

Добавянето на нов адрес не е част от демонстрацията.

' + '
'; } html += '
' + '

Начин на плащане (демо)

' + '
' + radioCard('co-payment', 'deferred', coState.payment === 'deferred', 'Отложено', 'Отложено плащане, падеж ' + DEMO.paymentDueDates[0] + ' — съгласно вашите търговски условия.') + radioCard('co-payment', 'advance', coState.payment === 'advance', 'Авансово', 'Плащане по проформа фактура преди експедиция.') + '
'; el('co-content').innerHTML = html; Array.prototype.forEach.call(document.querySelectorAll('input[name="co-delivery"]'), function (r) { r.addEventListener('change', function () { coState.delivery = r.value; renderCheckout(); }); }); Array.prototype.forEach.call(document.querySelectorAll('button[data-wh]'), function (b) { b.addEventListener('click', function () { coState.warehouse = b.getAttribute('data-wh'); renderCheckout(); }); }); Array.prototype.forEach.call(document.querySelectorAll('input[name="co-address"]'), function (r) { r.addEventListener('change', function () { coState.addressId = r.value; renderCheckout(); }); }); Array.prototype.forEach.call(document.querySelectorAll('input[name="co-payment"]'), function (r) { r.addEventListener('change', function () { coState.payment = r.value; renderCheckout(); }); }); el('co-summary').innerHTML = summaryHTML(coState.delivery, '' + '' + icon(IC.arrowLeft, 20) + 'Назад'); el('co-next').addEventListener('click', function () { coState.step = 3; renderCheckout(); window.scrollTo(0, 0); }); } function renderCheckoutStep3() { var ls = lines(); var m = DEMO.deliveryMethods.find(function (d) { return d.method === coState.delivery; }); var addr = DEMO.addresses.find(function (a) { return a.id === coState.addressId; }); var deliveryDetail = coState.delivery === 'pickup' ? 'Склад за изпълнение: ' + coState.warehouse : 'Адрес за доставка: ' + (addr ? addr.label : ''); var paymentDetail = coState.payment === 'deferred' ? 'Отложено плащане, падеж ' + DEMO.paymentDueDates[0] : 'Авансово — проформа фактура'; var html = ''; html += '
' + '

Продукти

' + '
'; html += '
' + '

Доставка и плащане

' + '
' + '
Начин на доставка
' + esc(m.label) + '
' + '
' + (coState.delivery === 'pickup' ? 'Склад за изпълнение' : 'Адрес за доставка') + '
' + esc(coState.delivery === 'pickup' ? coState.warehouse : (addr ? addr.label : '')) + '
' + '
Условие на плащане
' + esc(paymentDetail) + '
' + '
Фирма
' + esc(DEMO.company.name) + ' · ЕИК ' + esc(DEMO.company.eik) + '
' + '
'; el('co-content').innerHTML = html; el('co-summary').innerHTML = summaryHTML(coState.delivery, '' + ''); var subtotal = ls.reduce(function (s, l) { return s + l.lineTotal; }, 0); var blocked = window.ACM.creditState(subtotal) === 'blocked'; var submit = el('co-submit'); if (blocked) submit.disabled = true; submit.addEventListener('click', function () { var delivery = window.ACM.deliveryCost(coState.delivery, subtotal); var vat = (subtotal + delivery) * DEMO.vat; try { sessionStorage.setItem('acm-last-order', JSON.stringify({ number: DEMO.nextOrderNumber, total: subtotal + delivery + vat })); } catch (e) {} Cart.clear(); window.location.href = '/confirmation/'; }); el('co-back').addEventListener('click', function () { coState.step = 2; renderCheckout(); window.scrollTo(0, 0); }); } function renderCheckoutSteps() { var dots = document.querySelectorAll('#co-steps [data-step-dot]'); var labels = document.querySelectorAll('#co-steps li > span:last-child'); for (var i = 0; i < dots.length; i++) { var stepNo = i + 1; var done = stepNo < coState.step, current = stepNo === coState.step; dots[i].className = 'grid h-8 w-8 place-items-center rounded-full text-[13px] font-bold ' + (done || current ? 'bg-brand-green text-ink' : 'border border-border bg-surface text-muted'); labels[i].className = current ? 'font-medium text-ink' : 'text-muted'; } el('co-progress').style.width = ((coState.step - 1) / 2 * 100) + '%'; } function renderCheckout() { var ls = lines(); el('co-empty').hidden = ls.length > 0; el('co-full').hidden = ls.length === 0; if (!ls.length) return; renderCheckoutSteps(); if (coState.step === 2) renderCheckoutStep2(); else renderCheckoutStep3(); } /* ======================== Страница: Потвърждение ======================= */ function renderConfirmation() { var raw = null; try { raw = sessionStorage.getItem('acm-last-order'); } catch (e) {} if (!raw) { window.location.replace('/home/'); return; } try { var o = JSON.parse(raw); el('conf-number').textContent = o.number || DEMO.nextOrderNumber; } catch (e) { el('conf-number').textContent = DEMO.nextOrderNumber; } } /* ======================== Инициализация ================================ */ document.addEventListener('DOMContentLoaded', function () { var path = window.location.pathname; if (path.indexOf('/cart') === 0) { renderCartPage(); document.addEventListener('acm:cart-changed', renderCartPage); } else if (path.indexOf('/checkout') === 0) { renderCheckout(); document.addEventListener('acm:cart-changed', renderCheckout); } else if (path.indexOf('/confirmation') === 0) { renderConfirmation(); } }); })();