191 lines
4.6 KiB
JavaScript
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,
|
|
};
|
|
})();
|