215 lines
6 KiB
JavaScript
215 lines
6 KiB
JavaScript
|
|
/**
|
|||
|
|
* Cart Drawer Component
|
|||
|
|
* Manages the cart sidebar with add/remove/update functionality
|
|||
|
|
*/
|
|||
|
|
(function() {
|
|||
|
|
const drawer = document.getElementById('cart-drawer');
|
|||
|
|
const emptyState = document.querySelector('[data-cart-empty]');
|
|||
|
|
const itemsContainer = document.querySelector('[data-cart-items]');
|
|||
|
|
const checkoutBtn = document.querySelector('[data-cart-checkout]');
|
|||
|
|
const closeButtons = document.querySelectorAll('[data-cart-close]');
|
|||
|
|
|
|||
|
|
let currentCart = null;
|
|||
|
|
let cartInstance = null;
|
|||
|
|
|
|||
|
|
// Wait for ShopifyCart to be available
|
|||
|
|
function initCartDrawer() {
|
|||
|
|
if (typeof ShopifyCart === 'undefined') {
|
|||
|
|
setTimeout(initCartDrawer, 100);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cartInstance = new ShopifyCart({
|
|||
|
|
domain: 'nv7cqv-bu.myshopify.com',
|
|||
|
|
storefrontAccessToken: 'dec3d35a2554384d149c72927d1cfd1b'
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Initialize event listeners
|
|||
|
|
setupEventListeners();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function setupEventListeners() {
|
|||
|
|
// Close drawer
|
|||
|
|
closeButtons.forEach(btn => {
|
|||
|
|
btn.addEventListener('click', closeDrawer);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Checkout button
|
|||
|
|
checkoutBtn.addEventListener('click', () => {
|
|||
|
|
if (currentCart?.checkoutUrl) {
|
|||
|
|
window.location.href = currentCart.checkoutUrl;
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// Listen for custom cart update events
|
|||
|
|
document.addEventListener('cart:updated', (e) => {
|
|||
|
|
currentCart = e.detail.cart;
|
|||
|
|
renderCart();
|
|||
|
|
openDrawer();
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function openDrawer() {
|
|||
|
|
drawer.classList.add('is-open');
|
|||
|
|
document.body.style.overflow = 'hidden';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function closeDrawer() {
|
|||
|
|
drawer.classList.remove('is-open');
|
|||
|
|
document.body.style.overflow = '';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function renderCart() {
|
|||
|
|
if (!currentCart || !currentCart.lines || currentCart.lines.edges.length === 0) {
|
|||
|
|
emptyState.classList.remove('hidden');
|
|||
|
|
itemsContainer.classList.add('hidden');
|
|||
|
|
checkoutBtn.disabled = true;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
emptyState.classList.add('hidden');
|
|||
|
|
itemsContainer.classList.remove('hidden');
|
|||
|
|
checkoutBtn.disabled = false;
|
|||
|
|
|
|||
|
|
// Render cart items
|
|||
|
|
itemsContainer.innerHTML = currentCart.lines.edges.map(edge => {
|
|||
|
|
const item = edge.node;
|
|||
|
|
const merchandise = item.merchandise;
|
|||
|
|
|
|||
|
|
return `
|
|||
|
|
<div class="cart-item" data-line-id="${item.id}">
|
|||
|
|
<div class="cart-item__details">
|
|||
|
|
<h4 class="cart-item__title">${merchandise.product.title}</h4>
|
|||
|
|
${merchandise.title !== 'Default Title' ? `<p class="cart-item__variant">${merchandise.title}</p>` : ''}
|
|||
|
|
<p class="cart-item__price">${merchandise.price.amount} ${merchandise.price.currencyCode}</p>
|
|||
|
|
|
|||
|
|
<div class="cart-item__quantity">
|
|||
|
|
<button class="cart-item__qty-btn" data-action="decrease" data-line-id="${item.id}">−</button>
|
|||
|
|
<span class="cart-item__qty-value">${item.quantity}</span>
|
|||
|
|
<button class="cart-item__qty-btn" data-action="increase" data-line-id="${item.id}">+</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button class="cart-item__remove" data-action="remove" data-line-id="${item.id}">
|
|||
|
|
Retirer
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
}).join('');
|
|||
|
|
|
|||
|
|
// Attach event listeners to quantity buttons
|
|||
|
|
attachQuantityListeners();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function attachQuantityListeners() {
|
|||
|
|
const buttons = itemsContainer.querySelectorAll('[data-action]');
|
|||
|
|
|
|||
|
|
buttons.forEach(btn => {
|
|||
|
|
btn.addEventListener('click', async (e) => {
|
|||
|
|
const action = e.target.dataset.action;
|
|||
|
|
const lineId = e.target.dataset.lineId;
|
|||
|
|
|
|||
|
|
await handleQuantityChange(action, lineId);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
async function handleQuantityChange(action, lineId) {
|
|||
|
|
if (!cartInstance || !currentCart) return;
|
|||
|
|
|
|||
|
|
// Find the line item
|
|||
|
|
const line = currentCart.lines.edges.find(edge => edge.node.id === lineId);
|
|||
|
|
if (!line) return;
|
|||
|
|
|
|||
|
|
const currentQty = line.node.quantity;
|
|||
|
|
let newQty = currentQty;
|
|||
|
|
|
|||
|
|
if (action === 'increase') {
|
|||
|
|
newQty = currentQty + 1;
|
|||
|
|
} else if (action === 'decrease') {
|
|||
|
|
newQty = Math.max(0, currentQty - 1);
|
|||
|
|
} else if (action === 'remove') {
|
|||
|
|
newQty = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Update cart via API
|
|||
|
|
try {
|
|||
|
|
itemsContainer.classList.add('is-loading');
|
|||
|
|
|
|||
|
|
const query = `
|
|||
|
|
mutation cartLinesUpdate($cartId: ID!, $lines: [CartLineUpdateInput!]!) {
|
|||
|
|
cartLinesUpdate(cartId: $cartId, lines: $lines) {
|
|||
|
|
cart {
|
|||
|
|
id
|
|||
|
|
checkoutUrl
|
|||
|
|
lines(first: 10) {
|
|||
|
|
edges {
|
|||
|
|
node {
|
|||
|
|
id
|
|||
|
|
quantity
|
|||
|
|
merchandise {
|
|||
|
|
... on ProductVariant {
|
|||
|
|
id
|
|||
|
|
title
|
|||
|
|
price {
|
|||
|
|
amount
|
|||
|
|
currencyCode
|
|||
|
|
}
|
|||
|
|
product {
|
|||
|
|
title
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
userErrors {
|
|||
|
|
field
|
|||
|
|
message
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
`;
|
|||
|
|
|
|||
|
|
const data = await cartInstance.query(query, {
|
|||
|
|
cartId: currentCart.id,
|
|||
|
|
lines: [{
|
|||
|
|
id: lineId,
|
|||
|
|
quantity: newQty
|
|||
|
|
}]
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (data.cartLinesUpdate.userErrors.length > 0) {
|
|||
|
|
throw new Error(data.cartLinesUpdate.userErrors[0].message);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
currentCart = data.cartLinesUpdate.cart;
|
|||
|
|
renderCart();
|
|||
|
|
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('Error updating cart:', error);
|
|||
|
|
alert('Erreur lors de la mise à jour du panier');
|
|||
|
|
} finally {
|
|||
|
|
itemsContainer.classList.remove('is-loading');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Public API
|
|||
|
|
window.CartDrawer = {
|
|||
|
|
open: openDrawer,
|
|||
|
|
close: closeDrawer,
|
|||
|
|
updateCart: (cart) => {
|
|||
|
|
currentCart = cart;
|
|||
|
|
renderCart();
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// Initialize when DOM is ready
|
|||
|
|
if (document.readyState === 'loading') {
|
|||
|
|
document.addEventListener('DOMContentLoaded', initCartDrawer);
|
|||
|
|
} else {
|
|||
|
|
initCartDrawer();
|
|||
|
|
}
|
|||
|
|
})();
|