333 lines
8.0 KiB
JavaScript
333 lines
8.0 KiB
JavaScript
/**
|
|
* Shared Cart and Wishlist Utilities
|
|
* Extracted from duplicated code across multiple pages
|
|
*/
|
|
|
|
const CartUtils = {
|
|
/**
|
|
* Get cart from localStorage
|
|
* @returns {Array} Cart items
|
|
*/
|
|
getCart() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem("skyart_cart") || "[]");
|
|
} catch (error) {
|
|
console.error("Error loading cart:", error);
|
|
return [];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Save cart to localStorage
|
|
* @param {Array} cart - Cart items
|
|
*/
|
|
saveCart(cart) {
|
|
try {
|
|
localStorage.setItem("skyart_cart", JSON.stringify(cart));
|
|
this.updateCartBadge();
|
|
} catch (error) {
|
|
console.error("Error saving cart:", error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Add item to cart
|
|
* @param {Object} product - Product to add
|
|
* @param {number} quantity - Quantity to add
|
|
* @param {string} variant - Selected variant
|
|
*/
|
|
addToCart(product, quantity = 1, variant = null) {
|
|
const cart = this.getCart();
|
|
const cartKey = variant ? `${product.id}-${variant}` : product.id;
|
|
|
|
const existingIndex = cart.findIndex((item) => {
|
|
const itemKey = item.variant
|
|
? `${item.productId}-${item.variant}`
|
|
: item.productId;
|
|
return itemKey === cartKey;
|
|
});
|
|
|
|
if (existingIndex >= 0) {
|
|
cart[existingIndex].quantity += quantity;
|
|
} else {
|
|
cart.push({
|
|
productId: product.id,
|
|
name: product.name,
|
|
price: product.price,
|
|
image: product.images?.[0]?.image_url || product.imageurl,
|
|
quantity,
|
|
variant,
|
|
slug: product.slug,
|
|
});
|
|
}
|
|
|
|
this.saveCart(cart);
|
|
return cart;
|
|
},
|
|
|
|
/**
|
|
* Remove item from cart
|
|
* @param {string} productId - Product ID to remove
|
|
* @param {string} variant - Variant to remove
|
|
*/
|
|
removeFromCart(productId, variant = null) {
|
|
const cart = this.getCart();
|
|
const cartKey = variant ? `${productId}-${variant}` : productId;
|
|
|
|
const filtered = cart.filter((item) => {
|
|
const itemKey = item.variant
|
|
? `${item.productId}-${item.variant}`
|
|
: item.productId;
|
|
return itemKey !== cartKey;
|
|
});
|
|
|
|
this.saveCart(filtered);
|
|
return filtered;
|
|
},
|
|
|
|
/**
|
|
* Update cart item quantity
|
|
* @param {string} productId - Product ID
|
|
* @param {number} quantity - New quantity
|
|
* @param {string} variant - Variant
|
|
*/
|
|
updateQuantity(productId, quantity, variant = null) {
|
|
const cart = this.getCart();
|
|
const cartKey = variant ? `${productId}-${variant}` : productId;
|
|
|
|
const index = cart.findIndex((item) => {
|
|
const itemKey = item.variant
|
|
? `${item.productId}-${item.variant}`
|
|
: item.productId;
|
|
return itemKey === cartKey;
|
|
});
|
|
|
|
if (index >= 0) {
|
|
if (quantity <= 0) {
|
|
cart.splice(index, 1);
|
|
} else {
|
|
cart[index].quantity = quantity;
|
|
}
|
|
this.saveCart(cart);
|
|
}
|
|
|
|
return cart;
|
|
},
|
|
|
|
/**
|
|
* Get cart total
|
|
* @returns {number} Total price
|
|
*/
|
|
getCartTotal() {
|
|
const cart = this.getCart();
|
|
return cart.reduce((total, item) => {
|
|
return total + parseFloat(item.price) * item.quantity;
|
|
}, 0);
|
|
},
|
|
|
|
/**
|
|
* Update cart badge count
|
|
*/
|
|
updateCartBadge() {
|
|
const cart = this.getCart();
|
|
const count = cart.reduce((sum, item) => sum + item.quantity, 0);
|
|
const badge = document.querySelector(".cart-badge");
|
|
if (badge) {
|
|
badge.textContent = count;
|
|
badge.style.display = count > 0 ? "flex" : "none";
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Clear cart
|
|
*/
|
|
clearCart() {
|
|
localStorage.removeItem("skyart_cart");
|
|
this.updateCartBadge();
|
|
},
|
|
};
|
|
|
|
const WishlistUtils = {
|
|
/**
|
|
* Get wishlist from localStorage
|
|
* @returns {Array} Wishlist items
|
|
*/
|
|
getWishlist() {
|
|
try {
|
|
return JSON.parse(localStorage.getItem("wishlist") || "[]");
|
|
} catch (error) {
|
|
console.error("Error loading wishlist:", error);
|
|
return [];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Save wishlist to localStorage
|
|
* @param {Array} wishlist - Wishlist items
|
|
*/
|
|
saveWishlist(wishlist) {
|
|
try {
|
|
localStorage.setItem("wishlist", JSON.stringify(wishlist));
|
|
this.updateWishlistBadge();
|
|
} catch (error) {
|
|
console.error("Error saving wishlist:", error);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Add item to wishlist
|
|
* @param {Object} product - Product to add
|
|
*/
|
|
addToWishlist(product) {
|
|
const wishlist = this.getWishlist();
|
|
|
|
if (!wishlist.find((item) => item.id === product.id)) {
|
|
wishlist.push({
|
|
id: product.id,
|
|
name: product.name,
|
|
price: product.price,
|
|
image: product.images?.[0]?.image_url || product.imageurl,
|
|
slug: product.slug,
|
|
});
|
|
this.saveWishlist(wishlist);
|
|
}
|
|
|
|
return wishlist;
|
|
},
|
|
|
|
/**
|
|
* Remove item from wishlist
|
|
* @param {string} productId - Product ID to remove
|
|
*/
|
|
removeFromWishlist(productId) {
|
|
const wishlist = this.getWishlist();
|
|
const filtered = wishlist.filter((item) => item.id !== productId);
|
|
this.saveWishlist(filtered);
|
|
return filtered;
|
|
},
|
|
|
|
/**
|
|
* Check if product is in wishlist
|
|
* @param {string} productId - Product ID
|
|
* @returns {boolean} True if in wishlist
|
|
*/
|
|
isInWishlist(productId) {
|
|
const wishlist = this.getWishlist();
|
|
return wishlist.some((item) => item.id === productId);
|
|
},
|
|
|
|
/**
|
|
* Update wishlist badge count
|
|
*/
|
|
updateWishlistBadge() {
|
|
const wishlist = this.getWishlist();
|
|
const badge = document.querySelector(".wishlist-badge");
|
|
if (badge) {
|
|
badge.textContent = wishlist.length;
|
|
badge.style.display = wishlist.length > 0 ? "flex" : "none";
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Clear wishlist
|
|
*/
|
|
clearWishlist() {
|
|
localStorage.removeItem("wishlist");
|
|
this.updateWishlistBadge();
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Format price for display
|
|
* @param {number} price - Price to format
|
|
* @returns {string} Formatted price
|
|
*/
|
|
const formatPrice = (price) => {
|
|
return `$${parseFloat(price).toFixed(2)}`;
|
|
};
|
|
|
|
/**
|
|
* Format date for display
|
|
* @param {string} dateString - ISO date string
|
|
* @returns {string} Formatted date
|
|
*/
|
|
const formatDate = (dateString) => {
|
|
const date = new Date(dateString);
|
|
return date.toLocaleDateString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Debounce function
|
|
* @param {Function} func - Function to debounce
|
|
* @param {number} wait - Wait time in ms
|
|
* @returns {Function} Debounced function
|
|
*/
|
|
const debounce = (func, wait) => {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Show notification toast
|
|
* @param {string} message - Message to display
|
|
* @param {string} type - Type: success, error, info
|
|
*/
|
|
const showNotification = (message, type = "success") => {
|
|
// Check if a notification container exists
|
|
let container = document.querySelector(".notification-container");
|
|
if (!container) {
|
|
container = document.createElement("div");
|
|
container.className = "notification-container";
|
|
container.style.cssText = `
|
|
position: fixed;
|
|
top: 100px;
|
|
right: 20px;
|
|
z-index: 10000;
|
|
`;
|
|
document.body.appendChild(container);
|
|
}
|
|
|
|
const notification = document.createElement("div");
|
|
notification.className = `notification notification-${type}`;
|
|
notification.style.cssText = `
|
|
background: ${
|
|
type === "success" ? "#10b981" : type === "error" ? "#ef4444" : "#3b82f6"
|
|
};
|
|
color: white;
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
margin-bottom: 10px;
|
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
|
animation: slideIn 0.3s ease-out;
|
|
`;
|
|
notification.textContent = message;
|
|
|
|
container.appendChild(notification);
|
|
|
|
setTimeout(() => {
|
|
notification.style.animation = "slideOut 0.3s ease-out";
|
|
setTimeout(() => notification.remove(), 300);
|
|
}, 3000);
|
|
};
|
|
|
|
// Export for use in other scripts
|
|
if (typeof window !== "undefined") {
|
|
window.CartUtils = CartUtils;
|
|
window.WishlistUtils = WishlistUtils;
|
|
window.formatPrice = formatPrice;
|
|
window.formatDate = formatDate;
|
|
window.debounce = debounce;
|
|
window.showNotification = showNotification;
|
|
}
|