(() => { 'use strict'; const headers = { 'Content-Type': 'application/json', 'x-lang': 'en' }; async function request(path, options = {}) { const response = await fetch(path, { credentials: 'include', headers: { ...headers, ...(options.headers || {}) }, ...options }); const payload = await response.json().catch(() => ({})); if (!response.ok || payload.err) { throw new Error(payload.errorDetail || payload.message || 'The request could not be completed.'); } return payload.data ?? payload; } function showToast(message, type = 'default') { const container = document.getElementById('toast-container'); if (!container) return; const toast = document.createElement('div'); toast.className = `toast${type === 'default' ? '' : ` toast--${type}`}`; toast.textContent = message; container.appendChild(toast); window.setTimeout(() => toast.remove(), 3000); } function updateCartCount(cart) { const count = Number(cart?.computed?.itemcount || 0); document.querySelectorAll('[data-cart-count]').forEach((badge) => { badge.textContent = String(count); badge.hidden = count === 0; }); } async function refreshCart() { try { const cart = await request('/api/v1/cart/retrieve'); updateCartCount(cart); return cart; } catch { return null; } } async function addToCart({ productId, skuId, vendorCode, quantity }) { if (!productId || !skuId || !vendorCode) { throw new Error('This book does not have a purchasable SKU.'); } const cart = await request('/api/v1/cart/add', { method: 'POST', body: JSON.stringify({ productId, skuId, vendorCode, quantity }) }); updateCartCount(cart); showToast('Added to cart', 'success'); } function bindCartButtons() { document.querySelectorAll('[data-add-to-cart]').forEach((button) => { button.addEventListener('click', async () => { button.disabled = true; try { await addToCart({ productId: button.dataset.productId, skuId: button.dataset.skuId, vendorCode: button.dataset.vendorCode, quantity: 1 }); } catch (error) { showToast(error.message, 'error'); } finally { button.disabled = false; } }); }); const detailButton = document.querySelector('[data-add-product]'); const skuSelect = document.querySelector('[data-sku-select]'); if (detailButton && skuSelect) { detailButton.addEventListener('click', async () => { const option = skuSelect.options[skuSelect.selectedIndex]; const quantity = Math.max(1, Number(document.querySelector('[data-quantity]')?.value || 1)); detailButton.disabled = true; try { await addToCart({ productId: detailButton.dataset.productId, skuId: option.value, vendorCode: option.dataset.vendorCode, quantity }); } catch (error) { showToast(error.message, 'error'); } finally { detailButton.disabled = false; } }); } } async function updateAccountLink() { try { const state = await request('/api/v1/account/customer/isloggedin'); if (!state.isLoggedIn) return; document.querySelectorAll('[data-account-link]').forEach((link) => { link.href = '/api/v1/site/orders/history'; link.querySelector('small').textContent = 'My account'; }); } catch { // Anonymous browsing is expected. } } document.querySelectorAll('[data-current-year]').forEach((node) => { node.textContent = String(new Date().getFullYear()); }); bindCartButtons(); refreshCart(); updateAccountLink(); window.CampusBookHouse = { request, refreshCart, showToast, updateCartCount }; })();