2
0
Files
Royal-Pop-Accessory/Store/public/scripts/royal-pop-cart.js
T
2026-06-23 18:50:37 +01:00

191 lines
4.6 KiB
JavaScript

(function () {
const ROYAL_POP_CART_KEY = "royal-pop-cart";
const ROYAL_POP_BUILDER_KEY = "royal-pop-builder-selection";
const ROYAL_POP_CART_LIMIT = Number.POSITIVE_INFINITY;
const isBrowser = () => typeof window !== "undefined" && typeof window.localStorage !== "undefined";
const readJson = (key, fallback) => {
if (!isBrowser()) return fallback;
try {
const raw = window.localStorage.getItem(key);
if (!raw) return fallback;
return JSON.parse(raw);
} catch {
return fallback;
}
};
const writeJson = (key, value) => {
if (!isBrowser()) return;
try {
window.localStorage.setItem(key, JSON.stringify(value));
} catch {
// Ignore storage write failures.
}
};
const createItemId = () => {
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
return crypto.randomUUID();
}
return `rp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
};
const normalizeSelection = (selection) => ({
style: selection && selection.style === "A" ? "A" : "B",
colorwayId: (selection && selection.colorwayId) || "sorbet-pop-multi-color",
finishId: (selection && selection.finishId) || "silver",
quantity: Math.max(1, Math.round(Number(selection && selection.quantity) || 1)),
});
const loadBuilderSelection = () => {
const selection = readJson(ROYAL_POP_BUILDER_KEY, null);
if (!selection) return null;
return normalizeSelection(selection);
};
const saveBuilderSelection = (selection) => {
writeJson(ROYAL_POP_BUILDER_KEY, normalizeSelection(selection));
};
const loadCart = () => {
const items = readJson(ROYAL_POP_CART_KEY, []);
return items
.filter((item) => item && item.colorwayId && item.finishId)
.map((item) => ({
id: item.id || createItemId(),
style: item.style === "A" ? "A" : "B",
colorwayId: String(item.colorwayId),
finishId: String(item.finishId),
quantity: Math.max(1, Math.round(Number(item.quantity) || 1)),
}))
;
};
const saveCart = (items) => {
writeJson(
ROYAL_POP_CART_KEY,
items.map((item) => ({
...item,
quantity: Math.max(1, Math.round(Number(item.quantity) || 1)),
})),
);
};
const getCartCount = () => loadCart().reduce((sum, item) => sum + Math.max(1, Number(item.quantity) || 1), 0);
const addSelectionToCart = (selection) => {
const normalized = normalizeSelection(selection || {});
const currentCart = loadCart();
const matchingIndex = currentCart.findIndex(
(item) =>
item.style === normalized.style &&
item.colorwayId === normalized.colorwayId &&
item.finishId === normalized.finishId,
);
let nextCart;
if (matchingIndex >= 0) {
nextCart = currentCart.map((item, index) =>
index === matchingIndex
? {
...item,
quantity: Math.max(1, Number(item.quantity) || 1) + normalized.quantity,
}
: item,
);
} else {
nextCart = [
...currentCart,
{
id: createItemId(),
style: normalized.style,
colorwayId: normalized.colorwayId,
finishId: normalized.finishId,
quantity: normalized.quantity,
},
];
}
saveCart(nextCart);
return {
cart: nextCart,
addedCount: normalized.quantity,
isFull: false,
};
};
const removeCartItem = (itemId) => {
const currentCart = loadCart();
const nextCart = currentCart.filter((item) => item.id !== itemId);
saveCart(nextCart);
return nextCart;
};
const getEffectiveCart = () => {
const cart = loadCart();
if (cart.length > 0) return cart;
const selection = loadBuilderSelection();
if (!selection) return [];
return [{
id: createItemId(),
style: selection.style,
colorwayId: selection.colorwayId,
finishId: selection.finishId,
quantity: selection.quantity,
}];
};
const groupCartItems = (items) => {
const groups = new Map();
(items || []).forEach((item) => {
const key = `${item.style}::${item.colorwayId}::${item.finishId}`;
const current = groups.get(key);
const itemQuantity = Math.max(1, Math.round(Number(item.quantity) || 1));
if (current) {
current.quantity += itemQuantity;
return;
}
groups.set(key, {
style: item.style,
colorwayId: item.colorwayId,
finishId: item.finishId,
quantity: itemQuantity,
});
});
return Array.from(groups.values());
};
const clearCart = () => {
if (!isBrowser()) return;
window.localStorage.removeItem(ROYAL_POP_CART_KEY);
};
window.RoyalPopCart = {
ROYAL_POP_CART_KEY,
ROYAL_POP_BUILDER_KEY,
ROYAL_POP_CART_LIMIT,
loadBuilderSelection,
saveBuilderSelection,
loadCart,
saveCart,
getCartCount,
addSelectionToCart,
removeCartItem,
getEffectiveCart,
groupCartItems,
clearCart,
};
})();