/* ============================================================ OmahCitra Store - Aplikasi (jQuery) Fitur: Katalog, Keranjang, Checkout, Pengiriman, Pembayaran ============================================================ */ $(function () { "use strict"; // ---------- State ---------- const cart = {}; // { id: qty } let activeCat = "Semua"; let searchTerm = ""; let selectedCourier = null; let selectedPayment = null; // ---------- Helpers ---------- const rupiah = (n) => "Rp" + Number(n).toLocaleString("id-ID"); const $view = (name) => { $(".view").removeClass("active"); $("#view-" + name).addClass("active"); window.scrollTo(0, 0); }; const toast = (msg) => { const $t = $("#toast").text(msg).addClass("show"); clearTimeout(toast._t); toast._t = setTimeout(() => $t.removeClass("show"), 1800); }; // ---------- Category nav ---------- function buildCats() { const cats = ["Semua", ...new Set(PRODUCTS.map(p => p.category))]; const $nav = $("#catNav").empty(); cats.forEach(c => { $("
") .addClass("cat-pill" + (c === activeCat ? " active" : "")) .text(c) .on("click", function () { activeCat = c; buildCats(); renderCatalog(); }) .appendTo($nav); }); } // ---------- Catalog ---------- function renderCatalog() { const grid = $("#productGrid").empty(); const term = searchTerm.toLowerCase(); const list = PRODUCTS.filter(p => { const okCat = activeCat === "Semua" || p.category === activeCat; const okSearch = !term || p.name.toLowerCase().includes(term) || p.category.toLowerCase().includes(term) || p.desc.toLowerCase().includes(term); return okCat && okSearch; }); $("#emptyNote").toggle(list.length === 0); list.forEach(p => { const card = $(`
${p.emoji}
${p.category}${p.badge ? `${p.badge}` : ""}
${p.name}
★ ${p.rating} · ${p.sold.toLocaleString("id-ID")} terjual
${rupiah(p.price)}
`); card.find(".pc-btn").on("click", () => addToCart(p.id)); card.appendTo(grid); }); } // ---------- Cart ops ---------- function addToCart(id) { cart[id] = (cart[id] || 0) + 1; updateCartCount(); toast("Ditambahkan ke keranjang"); } function setQty(id, qty) { if (qty <= 0) delete cart[id]; else cart[id] = qty; updateCartCount(); renderCart(); } function updateCartCount() { const n = Object.values(cart).reduce((a, b) => a + b, 0); $("#cartCount").text(n); } function cartSubtotal() { return Object.entries(cart).reduce((sum, [id, q]) => { const p = PRODUCTS.find(x => x.id === id); return sum + (p ? p.price * q : 0); }, 0); } // ---------- Render cart ---------- function renderCart() { const $list = $("#cartItems").empty(); const ids = Object.keys(cart); if (ids.length === 0) { $("#cartEmpty").show(); $("#cartSummary").hide(); return; } $("#cartEmpty").hide(); $("#cartSummary").show(); ids.forEach(id => { const p = PRODUCTS.find(x => x.id === id); const qty = cart[id]; const row = $(`
${p.emoji}

${p.name}

${rupiah(p.price)} / pcs
${qty}
${rupiah(p.price * qty)}
`); row.find(".inc").on("click", () => setQty(id, qty + 1)); row.find(".dec").on("click", () => setQty(id, qty - 1)); row.find(".rm").on("click", () => { delete cart[id]; updateCartCount(); renderCart(); toast("Dihapus"); }); row.appendTo($list); }); $("#sumSubtotal").text(rupiah(cartSubtotal())); } // ---------- Checkout ---------- function buildCheckout() { // couriers const $c = $("#courierOptions").empty(); COURIERS.forEach(co => { const opt = $(` `); opt.find("input").on("change", () => { selectedCourier = co; $(".opt", $c).removeClass("selected"); opt.addClass("selected"); updateOrderSummary(); }); opt.appendTo($c); }); // payments const $p = $("#paymentOptions").empty(); PAYMENTS.forEach(pm => { const opt = $(` `); opt.find("input").on("change", () => { selectedPayment = pm; $(".opt", $p).removeClass("selected"); opt.addClass("selected"); }); opt.appendTo($p); }); renderOrderItems(); updateOrderSummary(); } function renderOrderItems() { const $o = $("#orderItems").empty(); Object.entries(cart).forEach(([id, q]) => { const p = PRODUCTS.find(x => x.id === id); $(`
${p.emoji} ${p.name} ×${q}${rupiah(p.price * q)}
`).appendTo($o); }); } function updateOrderSummary() { const sub = cartSubtotal(); const ship = selectedCourier ? selectedCourier.fee : 0; $("#coSubtotal").text(rupiah(sub)); $("#coShipping").text(selectedCourier ? rupiah(ship) : "Pilih kurir"); $("#coTotal").text(rupiah(sub + ship)); } // ---------- Place order ---------- function placeOrder() { if (Object.keys(cart).length === 0) { toast("Keranjang kosong"); return; } const name = $("#custName").val().trim(); const addr = $("#custAddr").val().trim(); const phone = $("#custPhone").val().trim(); if (!name || !addr || !phone) { toast("Lengkapi data penerima"); return; } if (!selectedCourier) { toast("Pilih kurir pengiriman"); return; } if (!selectedPayment) { toast("Pilih metode pembayaran"); return; } const orderNo = "OC" + Date.now().toString().slice(-8); const sub = cartSubtotal(); const total = sub + selectedCourier.fee; $("#orderNo").text(orderNo); $("#doneDetail").html(`
Nama: ${name}
Alamat: ${addr}
HP: ${phone}
Kurir: ${selectedCourier.name} (${selectedCourier.etd})
Pembayaran: ${selectedPayment.name}
Total: ${rupiah(total)}
`); // reset for (const k in cart) delete cart[k]; updateCartCount(); selectedCourier = null; selectedPayment = null; $("#custName,#custAddr,#custPhone").val(""); $view("done"); } // ---------- Events ---------- $("#cartBtn").on("click", () => { renderCart(); $view("cart"); }); $("#toCheckout").on("click", () => { if (Object.keys(cart).length === 0) { toast("Keranjang kosong"); return; } buildCheckout(); $view("checkout"); }); $("#placeOrder").on("click", placeOrder); $("#searchInput").on("input", function () { searchTerm = $(this).val(); renderCatalog(); }); // navigasi via data-view (brand & tombol) $(document).on("click", "[data-view]", function (e) { e.preventDefault(); const v = $(this).data("view"); if (v === "cart") renderCart(); if (v === "checkout") buildCheckout(); $view(v); }); // ---------- Init ---------- buildCats(); renderCatalog(); updateCartCount(); });