159 lines
3.3 KiB
JavaScript
159 lines
3.3 KiB
JavaScript
/**
|
|
* Cart Store
|
|
* Manages shopping cart state with localStorage persistence
|
|
* Dispatches 'cart-updated' events when cart changes
|
|
*/
|
|
|
|
const CART_STORAGE_KEY = "milinda-cart";
|
|
|
|
class CartStore {
|
|
constructor() {
|
|
this.items = this.loadFromStorage();
|
|
}
|
|
|
|
/**
|
|
* Load cart from localStorage
|
|
*/
|
|
loadFromStorage() {
|
|
try {
|
|
const stored = localStorage.getItem(CART_STORAGE_KEY);
|
|
return stored ? JSON.parse(stored) : [];
|
|
} catch (e) {
|
|
console.error("Failed to load cart from storage:", e);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save cart to localStorage
|
|
*/
|
|
saveToStorage() {
|
|
try {
|
|
localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(this.items));
|
|
} catch (e) {
|
|
console.error("Failed to save cart to storage:", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dispatch cart-updated event
|
|
*/
|
|
notifyUpdate() {
|
|
window.dispatchEvent(
|
|
new CustomEvent("cart-updated", {
|
|
detail: {
|
|
items: this.items,
|
|
count: this.getItemCount(),
|
|
total: this.getTotal(),
|
|
},
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Add item to cart
|
|
* @param {Object} item - Item to add { title, author, price, type, image }
|
|
*/
|
|
addItem(item) {
|
|
// Check if item already exists (by title and type)
|
|
const existingIndex = this.items.findIndex(
|
|
(i) => i.title === item.title && i.type === item.type
|
|
);
|
|
|
|
if (existingIndex >= 0) {
|
|
// Increment quantity
|
|
this.items[existingIndex].quantity += 1;
|
|
} else {
|
|
// Add new item
|
|
this.items.push({
|
|
...item,
|
|
quantity: 1,
|
|
addedAt: Date.now(),
|
|
});
|
|
}
|
|
|
|
this.saveToStorage();
|
|
this.notifyUpdate();
|
|
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* Remove item from cart
|
|
* @param {number} index - Index of item to remove
|
|
*/
|
|
removeItem(index) {
|
|
if (index >= 0 && index < this.items.length) {
|
|
this.items.splice(index, 1);
|
|
this.saveToStorage();
|
|
this.notifyUpdate();
|
|
}
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* Update item quantity
|
|
* @param {number} index - Index of item
|
|
* @param {number} quantity - New quantity
|
|
*/
|
|
updateQuantity(index, quantity) {
|
|
if (index >= 0 && index < this.items.length) {
|
|
if (quantity <= 0) {
|
|
this.removeItem(index);
|
|
} else {
|
|
this.items[index].quantity = quantity;
|
|
this.saveToStorage();
|
|
this.notifyUpdate();
|
|
}
|
|
}
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* Clear all items from cart
|
|
*/
|
|
clear() {
|
|
this.items = [];
|
|
this.saveToStorage();
|
|
this.notifyUpdate();
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* Get all items
|
|
*/
|
|
getItems() {
|
|
return this.items;
|
|
}
|
|
|
|
/**
|
|
* Get total item count (sum of quantities)
|
|
*/
|
|
getItemCount() {
|
|
return this.items.reduce((sum, item) => sum + item.quantity, 0);
|
|
}
|
|
|
|
/**
|
|
* Get cart total price
|
|
*/
|
|
getTotal() {
|
|
return this.items.reduce((sum, item) => {
|
|
// Parse price like "€ 24,95" to number
|
|
const priceStr = item.price || "0";
|
|
const price = parseFloat(
|
|
priceStr.replace(/[€$£\s]/g, "").replace(",", ".")
|
|
);
|
|
return sum + price * item.quantity;
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
// Create singleton instance
|
|
const cart = new CartStore();
|
|
|
|
// Export for module use
|
|
export default cart;
|
|
|
|
// Also attach to window for global access
|
|
window.cartStore = cart;
|