325 lines
11 KiB
JavaScript
325 lines
11 KiB
JavaScript
/**
|
|
* Cart functionality for marketplace pages
|
|
* Migrated from inline scripts to use apiJson and shared error handlers
|
|
*/
|
|
|
|
// Global variable to store product ID for removal
|
|
let productIdToRemove = null;
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialize cart functionality
|
|
console.log('Cart page loaded');
|
|
|
|
// Update My Orders visibility when cart page loads
|
|
if (typeof updateMyOrdersVisibility === 'function') {
|
|
updateMyOrdersVisibility();
|
|
}
|
|
|
|
// Initialize recommended products functionality
|
|
initializeRecommendedProducts();
|
|
|
|
// Add event listeners for quantity buttons
|
|
document.querySelectorAll('[data-action="increase"], [data-action="decrease"]').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const productId = this.getAttribute('data-product-id');
|
|
const action = this.getAttribute('data-action');
|
|
const currentQuantity = parseInt(this.parentElement.querySelector('span').textContent);
|
|
|
|
if (action === 'increase') {
|
|
updateQuantity(productId, currentQuantity + 1);
|
|
} else if (action === 'decrease') {
|
|
updateQuantity(productId, currentQuantity - 1);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Add event listeners for remove buttons
|
|
document.querySelectorAll('[data-action="remove"]').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const productId = this.getAttribute('data-product-id');
|
|
showRemoveItemModal(productId);
|
|
});
|
|
});
|
|
|
|
// Add event listener for clear cart button
|
|
const clearCartBtn = document.getElementById('clearCartBtn');
|
|
if (clearCartBtn) {
|
|
clearCartBtn.addEventListener('click', showClearCartModal);
|
|
}
|
|
|
|
// Add event listener for confirm clear cart button in modal
|
|
const confirmClearCartBtn = document.getElementById('confirmClearCartBtn');
|
|
if (confirmClearCartBtn) {
|
|
confirmClearCartBtn.addEventListener('click', clearCart);
|
|
}
|
|
|
|
// Add event listener for confirm remove item button in modal
|
|
const confirmRemoveItemBtn = document.getElementById('confirmRemoveItemBtn');
|
|
if (confirmRemoveItemBtn) {
|
|
confirmRemoveItemBtn.addEventListener('click', confirmRemoveItem);
|
|
}
|
|
|
|
// Add event listener for currency selector
|
|
const currencySelector = document.getElementById('currencySelector');
|
|
if (currencySelector) {
|
|
currencySelector.addEventListener('change', changeCurrency);
|
|
}
|
|
|
|
// Post-reload success toast for cart clear (marketplace view)
|
|
try {
|
|
if (sessionStorage.getItem('cartCleared') === '1') {
|
|
sessionStorage.removeItem('cartCleared');
|
|
showSuccessToast('Cart cleared successfully');
|
|
}
|
|
} catch (_) { /* storage may be blocked */ }
|
|
});
|
|
|
|
// Helper: zero Order Summary values and disable checkout when empty
|
|
function setMarketplaceSummaryEmpty() {
|
|
try {
|
|
const summaryCardBody = document.querySelector('.col-lg-4 .card .card-body');
|
|
if (!summaryCardBody) return;
|
|
// Update Subtotal and Total values to $0.00
|
|
summaryCardBody.querySelectorAll('.d-flex.justify-content-between').forEach(row => {
|
|
const spans = row.querySelectorAll('span');
|
|
if (spans.length >= 2) {
|
|
const label = spans[0].textContent.trim();
|
|
if (label.startsWith('Subtotal')) spans[1].textContent = '$0.00';
|
|
if (label === 'Total') spans[1].textContent = '$0.00';
|
|
}
|
|
});
|
|
// Disable checkout if present
|
|
const checkoutBtn = summaryCardBody.querySelector('.btn.btn-primary.btn-lg');
|
|
if (checkoutBtn) {
|
|
if (checkoutBtn.tagName === 'BUTTON') {
|
|
checkoutBtn.disabled = true;
|
|
} else {
|
|
checkoutBtn.classList.add('disabled');
|
|
checkoutBtn.setAttribute('aria-disabled', 'true');
|
|
checkoutBtn.setAttribute('tabindex', '-1');
|
|
}
|
|
}
|
|
} catch (_) { /* noop */ }
|
|
}
|
|
|
|
// Update item quantity using apiJson
|
|
async function updateQuantity(productId, newQuantity) {
|
|
if (newQuantity < 1) {
|
|
removeFromCart(productId);
|
|
return;
|
|
}
|
|
|
|
showLoading();
|
|
|
|
try {
|
|
const data = await window.apiJson(`/api/cart/item/${productId}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({
|
|
quantity: newQuantity
|
|
})
|
|
});
|
|
|
|
// Success - reload page to show updated cart
|
|
window.location.reload();
|
|
} catch (error) {
|
|
handleApiError(error, 'updating quantity');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// Show clear cart modal
|
|
function showClearCartModal() {
|
|
const modal = new bootstrap.Modal(document.getElementById('clearCartModal'));
|
|
modal.show();
|
|
}
|
|
|
|
// Show remove item modal
|
|
function showRemoveItemModal(productId) {
|
|
productIdToRemove = productId;
|
|
const modal = new bootstrap.Modal(document.getElementById('removeItemModal'));
|
|
modal.show();
|
|
}
|
|
|
|
// Confirm remove item (called from modal)
|
|
async function confirmRemoveItem() {
|
|
if (!productIdToRemove) return;
|
|
|
|
// Hide the modal first
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('removeItemModal'));
|
|
modal.hide();
|
|
|
|
await removeFromCart(productIdToRemove);
|
|
productIdToRemove = null;
|
|
}
|
|
|
|
// Remove item from cart using apiJson
|
|
async function removeFromCart(productId) {
|
|
showLoading();
|
|
|
|
try {
|
|
await window.apiJson(`/api/cart/item/${productId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
showSuccessToast('Item removed from cart');
|
|
|
|
// Remove the item from DOM immediately
|
|
const cartItem = document.querySelector(`[data-product-id="${productId}"]`);
|
|
if (cartItem) {
|
|
cartItem.remove();
|
|
}
|
|
|
|
// Notify globally and update navbar cart count
|
|
if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(); }
|
|
if (typeof window.updateCartCount === 'function') { window.updateCartCount(); }
|
|
|
|
// Update cart counts and check if cart is empty
|
|
await refreshCartContents();
|
|
} catch (error) {
|
|
handleApiError(error, 'removing item from cart');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// Clear entire cart using apiJson
|
|
async function clearCart() {
|
|
// Hide the modal first
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById('clearCartModal'));
|
|
modal.hide();
|
|
|
|
showLoading();
|
|
|
|
try {
|
|
await window.apiJson('/api/cart', { method: 'DELETE' });
|
|
|
|
// Emit and update counts, then reload to ensure consistent empty state
|
|
if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(0); }
|
|
if (typeof window.updateCartCount === 'function') { window.updateCartCount(); }
|
|
try { sessionStorage.setItem('cartCleared', '1'); } catch (_) { /* storage may be blocked */ }
|
|
setTimeout(() => { window.location.reload(); }, 50);
|
|
} catch (error) {
|
|
handleApiError(error, 'clearing cart');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// Change display currency using apiJson
|
|
async function changeCurrency() {
|
|
const currencySelector = document.getElementById('currencySelector');
|
|
const selectedCurrency = currencySelector.value;
|
|
|
|
showLoading();
|
|
|
|
try {
|
|
await window.apiJson('/api/user/currency', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
currency: selectedCurrency
|
|
})
|
|
});
|
|
|
|
// Reload page to show prices in new currency
|
|
window.location.reload();
|
|
} catch (error) {
|
|
handleApiError(error, 'changing currency');
|
|
} finally {
|
|
hideLoading();
|
|
}
|
|
}
|
|
|
|
// Refresh cart contents using apiJson
|
|
async function refreshCartContents() {
|
|
try {
|
|
// Fetch fresh cart data from server
|
|
const data = await window.apiJson('/api/cart', {
|
|
method: 'GET',
|
|
cache: 'no-store'
|
|
});
|
|
|
|
// Check if cart is empty and update UI accordingly
|
|
const cartItems = data.items || [];
|
|
if (cartItems.length === 0) {
|
|
// Show empty cart state
|
|
const cartContainer = document.querySelector('.cart-items-container');
|
|
if (cartContainer) {
|
|
cartContainer.innerHTML = `
|
|
<div class="text-center py-5">
|
|
<i class="bi bi-cart-x display-1 text-muted"></i>
|
|
<h3 class="mt-3">Your cart is empty</h3>
|
|
<p class="text-muted">Add some items to get started!</p>
|
|
<a href="/marketplace" class="btn btn-primary">Browse Marketplace</a>
|
|
</div>
|
|
`;
|
|
}
|
|
setMarketplaceSummaryEmpty();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error refreshing cart contents:', error);
|
|
// Don't show error toast for this background operation
|
|
}
|
|
}
|
|
|
|
// Add to cart functionality for product pages
|
|
async function addToCartFromPage(productId, quantity = 1, buttonElement = null) {
|
|
if (buttonElement) {
|
|
setButtonLoading(buttonElement, 'Adding...');
|
|
}
|
|
|
|
try {
|
|
await window.apiJson('/api/cart/add', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
product_id: productId,
|
|
quantity: quantity
|
|
})
|
|
});
|
|
|
|
if (buttonElement) {
|
|
setButtonSuccess(buttonElement, 'Added!');
|
|
}
|
|
showSuccessToast('Item added to cart');
|
|
|
|
// Update cart count in navbar
|
|
if (typeof window.updateCartCount === 'function') {
|
|
window.updateCartCount();
|
|
}
|
|
} catch (error) {
|
|
handleApiError(error, 'adding to cart', buttonElement);
|
|
}
|
|
}
|
|
|
|
// Utility functions
|
|
function showLoading() {
|
|
const overlay = document.getElementById('loadingOverlay');
|
|
if (overlay) {
|
|
overlay.classList.remove('d-none');
|
|
}
|
|
}
|
|
|
|
function hideLoading() {
|
|
const overlay = document.getElementById('loadingOverlay');
|
|
if (overlay) {
|
|
overlay.classList.add('d-none');
|
|
}
|
|
}
|
|
|
|
// Initialize recommended products functionality
|
|
function initializeRecommendedProducts() {
|
|
// Add event listeners for recommended product add-to-cart buttons
|
|
document.querySelectorAll('.recommended-product .add-to-cart-btn').forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const productId = this.dataset.productId;
|
|
if (productId) {
|
|
addToCartFromPage(productId, 1, this);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Make functions available globally for backward compatibility
|
|
window.addToCartFromPage = addToCartFromPage;
|
|
window.refreshCartContents = refreshCartContents;
|