webupdate
This commit is contained in:
332
website/public/assets/js/shared-utils.js
Normal file
332
website/public/assets/js/shared-utils.js
Normal file
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user