const productVariants = (window.shopConfig && window.shopConfig.productVariants) ? window.shopConfig.productVariants : []; var updateDebounceTimers = {}; var currentCartData = (window.shopConfig && window.shopConfig.initialCart) ? window.shopConfig.initialCart : null; function showCartError(msg) { $('#cart-error-banner').text(msg).slideDown(200); setTimeout(function() { $('#cart-error-banner').slideUp(200); }, 4000); } function updateVariantSelection() { const selectedOptions = {}; $('.variant-option').each(function() { selectedOptions[$(this).attr('name')] =$(this).val(); }); const matchedVariant = productVariants.find(edge => { return edge.node.selectedOptions.every(opt => selectedOptions[opt.name] === opt.value); }); if (matchedVariant) { $('#selected-variant-id').val(matchedVariant.node.id); const amt = parseFloat(matchedVariant.node.price.amount); const formattedPrice = (amt % 1 === 0) ? amt : amt.toFixed(2); const compareAtNode = matchedVariant.node.compareAtPrice; if (compareAtNode && compareAtNode.amount) { const compareAmt = parseFloat(compareAtNode.amount); if (compareAmt > amt) { const diff = compareAmt - amt; const formattedDiff = (diff % 1 === 0) ? diff : diff.toFixed(2); const formattedCompare = (compareAmt % 1 === 0) ? compareAmt : compareAmt.toFixed(2); $('#compare-diff').text('$' + formattedDiff);$('#compare-val').text('$' + formattedCompare);$('.compare_at').show(); } else { $('.compare_at').hide(); } } else { $('.compare_at').hide(); } const isAvailable = matchedVariant.node.availableForSale; if (isAvailable) { $('#price-val').text('$' + formattedPrice);$('#add-to-cart-btn').text('Add to Cart').prop('disabled', false); } else { $('#price-val').text('$' + formattedPrice);$('#add-to-cart-btn').text('Out of Stock').prop('disabled', true); } } } function openCart() { if (currentCartData) { renderCartDrawer(currentCartData); } else { $.ajax({ url: '/cart/get', type: 'GET', success: function(res) { if (res.success && res.cart) { renderCartDrawer(res.cart); } } }); } $('#cart-overlay').fadeIn(200); $('#cart-drawer').addClass('open'); $('html').addClass('no-scroll'); } function closeCart() { $('#cart-overlay').fadeOut(200); $('#cart-drawer').removeClass('open'); $('#cart-error-banner').hide(); $('html').removeClass('no-scroll'); } function renderCartDrawer(cart) { if (!cart) return; currentCartData = cart; let rawCheckoutUrl = cart.checkoutUrl || '#'; if (rawCheckoutUrl !== '#') { const analyticsParams = getShopifyAnalyticsParams(); if (analyticsParams) { rawCheckoutUrl += (rawCheckoutUrl.includes('?') ? '&' : '?') + analyticsParams; } } $('#checkout-link').attr('href', rawCheckoutUrl); const container = $('#cart-items'); container.empty(); let totalItemCount = 0; let computedSubtotal = 0; if (cart.lines && cart.lines.edges && cart.lines.edges.length > 0) { cart.lines.edges.forEach(edge => { const lineItem = edge.node; const lineId = lineItem.id; const qty = parseInt(lineItem.quantity, 10) || 1; totalItemCount += qty; const merch = lineItem.merchandise; const productTitle = merch.product ? merch.product.title : ''; const variantTitle = (merch.title && merch.title !== 'Default Title') ? ' (' + merch.title + ')' : ''; const title = productTitle + variantTitle; const imgUrl = (merch.product && merch.product.featuredImage && merch.product.featuredImage.url) ? merch.product.featuredImage.url : '/img/logo.png'; const unitPrice = parseFloat(merch.price.amount); computedSubtotal += (unitPrice * qty); const formattedUnitPrice = (unitPrice % 1 === 0) ? unitPrice : unitPrice.toFixed(2); const itemHtml = `
Your cart is currently empty.
'); $('#cart-subtotal').html('$0'); } $('#cart-count-total').text(totalItemCount); $('#nav-cart-count').text(totalItemCount > 0 ? totalItemCount : ''); } function adjustQuantityLocally(lineId, delta) { var safeSelector = CSS.escape(lineId); var itemEl = $('.cart-item[data-line-id="' + safeSelector + '"]'); if (!itemEl.length) return; var qtySpan = itemEl.find('.item-qty-display'); var currentQty = parseInt(qtySpan.text(), 10) || 1; var targetQty = currentQty + delta; if (targetQty < 1) return; qtySpan.text(targetQty); updateSubtotalInDOM(); if (updateDebounceTimers[lineId]) { clearTimeout(updateDebounceTimers[lineId]); } updateDebounceTimers[lineId] = setTimeout(function() { delete updateDebounceTimers[lineId]; executeQuantitySync(lineId, targetQty, 1); }, 400); } function updateSubtotalInDOM() { var totalQty = 0; var subtotal = 0; $('.cart-item').each(function() { var qty = parseInt($(this).find('.item-qty-display').text(), 10) || 0; var unitPrice = parseFloat($(this).attr('data-price')) || 0; totalQty += qty; subtotal += (qty * unitPrice); }); var formattedSubtotal = (subtotal % 1 === 0) ? subtotal : subtotal.toFixed(2); $('#cart-subtotal').html('$' + formattedSubtotal);$('#cart-count-total').text(totalQty); $('#nav-cart-count').text(totalQty > 0 ? totalQty : ''); } function executeQuantitySync(lineId, targetQty, attempt) { $.ajax({ url: '/cart/update', type: 'POST', contentType: 'application/json', data: JSON.stringify({ lineId: String(lineId), quantity: parseInt(targetQty, 10) }), success: function(res) { if (res.success && res.cart) { renderCartDrawer(res.cart); } else if (res.message && res.message.indexOf('Throttled') !== -1 && attempt <= 3) { setTimeout(function() { executeQuantitySync(lineId, targetQty, attempt + 1); }, 1200); } else { showCartError(res.message || 'Requested quantity is not available.'); $.ajax({ url: '/cart/get', type: 'GET', success: function(refreshedRes) { if (refreshedRes.success && refreshedRes.cart) { renderCartDrawer(refreshedRes.cart); } } }); } } }); } function removeLineItem(lineId) { if (updateDebounceTimers[lineId]) { clearTimeout(updateDebounceTimers[lineId]); delete updateDebounceTimers[lineId]; } $('.cart-item[data-line-id="' + lineId + '"]').fadeOut(200, function() { $(this).remove(); updateSubtotalInDOM(); }); $.ajax({ url: '/cart/remove', type: 'POST', contentType: 'application/json', data: JSON.stringify({ lineId: String(lineId) }), success: function(res) { if (res.success && res.cart) { renderCartDrawer(res.cart); } } }); } $(document).ready(function() {$(document).on('click', '#open-cart-btn', openCart); $(document).on('click', '#close-cart, #cart-overlay', closeCart); $(document).on('change', '.variant-option', updateVariantSelection); $(document).on('click', '#add-to-cart-btn', function() { const variantId = $('#selected-variant-id').val(); const btn = $(this); const drillingOption = $('select[name="drilling_option"]').val(); const drillingSku = $('#drilling_type_input').val(); if (drillingOption === 'standard' && !drillingSku) { showCartError('Please select a drilling style option.'); return; } btn.text('Adding...').prop('disabled', true); const itemsToAdd = [ { variantId: variantId, quantity: 1 } ]; if (drillingOption === 'standard' && drillingSku) { itemsToAdd.push({ variantId: drillingSku, quantity: 1 }); } $.ajax({ url: '/cart/add', type: 'POST', contentType: 'application/json', data: JSON.stringify({ items: itemsToAdd, variantId: variantId, drillingSku: (drillingOption === 'standard' ? drillingSku : null), quantity: 1 }), success: function(res) { btn.text('Add to Cart').prop('disabled', false); if (res.success && res.cart) { renderCartDrawer(res.cart); openCart(); } else { showCartError(res.message || 'Item is out of stock.'); } }, error: function() { btn.text('Add to Cart').prop('disabled', false); showCartError('An error occurred connecting to the server.'); } }); }); // Render initial cart state on document load if (currentCartData) { renderCartDrawer(currentCartData); } else { $.ajax({ url: '/cart/get', type: 'GET', success: function(res) { if (res.success && res.cart) { renderCartDrawer(res.cart); } } }); } });