Files
hoomat-store/lib/meshkee/cart.ts
T

118 lines
3.4 KiB
TypeScript

import type { CartLine, CartState } from "@/lib/meshkee/types";
function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === "object" ? (value as Record<string, unknown>) : {};
}
function asString(value: unknown): string {
return typeof value === "string" ? value : value == null ? "" : String(value);
}
function asNumber(value: unknown): number | null {
if (typeof value === "number" && Number.isFinite(value)) return value;
if (typeof value === "string" && value.trim() && !Number.isNaN(Number(value))) {
return Number(value);
}
return null;
}
export function emptyCart(): CartState {
return { items: [], subtotal: 0, total: 0 };
}
export function cartFromGuest(
items: Array<{
id: string;
name: string;
slug?: string;
price: number;
image?: string | null;
quantity: number;
}>,
): CartState {
const lines: CartLine[] = items.map((item) => ({
id: item.id,
storeItemVariantId: item.id,
name: item.name,
slug: item.slug,
image: item.image ?? null,
price: item.price,
quantity: item.quantity,
}));
const subtotal = lines.reduce((sum, line) => sum + line.price * line.quantity, 0);
return { items: lines, subtotal, total: subtotal };
}
export function normalizeCartResponse(payload: unknown): CartState {
const root = asRecord(payload);
const cart = asRecord(root.cart ?? root);
const source = Array.isArray(cart.items)
? cart.items
: Array.isArray(root.items)
? root.items
: [];
const items: CartLine[] = source.map((raw) => {
const item = asRecord(raw);
const product = asRecord(item.product);
const variant = asRecord(item.variant);
const storeItem = asRecord(item.storeItem);
const quantity = asNumber(item.quantity) ?? 1;
const price =
asNumber(item.unitPrice) ??
asNumber(item.price) ??
asNumber(item.discountedPrice) ??
asNumber(variant.discountedPrice) ??
asNumber(variant.price) ??
asNumber(storeItem.discountedPrice) ??
asNumber(storeItem.price) ??
0;
const selections = Array.isArray(item.selections)
? item.selections
: Array.isArray(variant.selections)
? variant.selections
: [];
const optionLabel = selections
.map((entry) => {
const row = asRecord(entry);
return asString(row.label || row.optionLabel || row.value);
})
.filter(Boolean)
.join(" / ");
return {
id: asString(item.id || item.itemId),
storeItemVariantId: asString(
item.storeItemVariantId || variant.id || storeItem.id || item.variantId,
),
name: asString(
item.productTitle ||
item.productNameFa ||
product.nameFa ||
product.name ||
product.title ||
storeItem.productTitle ||
storeItem.productNameFa ||
"محصول",
),
slug: asString(product.slug || item.productSlug || storeItem.productSlug) || undefined,
image:
asString(
item.productImage ||
item.image ||
product.image ||
product.thumbnailUrl ||
storeItem.productImage,
) || null,
price,
quantity,
optionLabel: optionLabel || undefined,
};
});
const subtotal =
asNumber(cart.subtotal) ?? items.reduce((sum, line) => sum + line.price * line.quantity, 0);
const total = asNumber(cart.total) ?? subtotal;
return { items, subtotal, total };
}