Version 1
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
(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,
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user