/* ============================================================
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();
});