120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
import type { CartItem } from "@/lib/cart-types";
|
|
|
|
/** Must match customer dashboard `GUEST_CART_STORAGE_KEY`. */
|
|
export const MESHKEE_GUEST_CART_KEY = "meshkee-guest-cart";
|
|
export const LEGACY_GUEST_CART_KEY = "sanihome-guest-cart";
|
|
export const GUEST_CART_URL_PARAM = "guestCart";
|
|
|
|
export type MeshkeeGuestCartItem = {
|
|
id: string;
|
|
name: string;
|
|
slug?: string;
|
|
price: number;
|
|
originalPrice?: number;
|
|
image: string | null;
|
|
quantity: number;
|
|
};
|
|
|
|
function cookieDomain(): string | undefined {
|
|
if (typeof window === "undefined") return undefined;
|
|
const host = window.location.hostname.toLowerCase();
|
|
if (host === "localhost" || host === "127.0.0.1") return undefined;
|
|
const parts = host.split(".").filter(Boolean);
|
|
if (parts.length < 2) return undefined;
|
|
return `.${parts.slice(-2).join(".")}`;
|
|
}
|
|
|
|
function parseItems(raw: string | null): CartItem[] {
|
|
if (!raw) return [];
|
|
try {
|
|
const parsed = JSON.parse(raw) as CartItem[];
|
|
return Array.isArray(parsed) ? parsed : [];
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/** Map storefront cart lines to the shared guest-cart shape (id = variant id). */
|
|
export function toMeshkeeGuestItems(items: CartItem[]): MeshkeeGuestCartItem[] {
|
|
const result: MeshkeeGuestCartItem[] = [];
|
|
for (const item of items) {
|
|
const variantId = (item.storeItemVariantId || item.id || "").trim();
|
|
if (!variantId) continue;
|
|
result.push({
|
|
id: variantId,
|
|
name: item.name || "محصول",
|
|
...(item.slug ? { slug: item.slug } : {}),
|
|
price: item.price,
|
|
image: item.image ?? null,
|
|
quantity: Math.max(1, Math.floor(item.quantity) || 1),
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export function encodeGuestCartForUrl(items: CartItem[]): string {
|
|
const payload = toMeshkeeGuestItems(items);
|
|
const json = JSON.stringify(payload);
|
|
return btoa(unescape(encodeURIComponent(json)))
|
|
.replace(/\+/g, "-")
|
|
.replace(/\//g, "_")
|
|
.replace(/=+$/, "");
|
|
}
|
|
|
|
function writeSharedCookie(items: MeshkeeGuestCartItem[]) {
|
|
if (typeof document === "undefined") return;
|
|
const domain = cookieDomain();
|
|
const maxAge = 60 * 60 * 24 * 30;
|
|
const encoded = encodeURIComponent(
|
|
JSON.stringify(
|
|
items.map(({ id, name, slug, price, originalPrice, quantity }) => ({
|
|
id,
|
|
name,
|
|
slug,
|
|
price,
|
|
originalPrice,
|
|
quantity,
|
|
image: null as string | null,
|
|
})),
|
|
),
|
|
);
|
|
if (encoded.length > 3500) return;
|
|
let cookie = `${MESHKEE_GUEST_CART_KEY}=${encoded}; path=/; max-age=${maxAge}; SameSite=Lax`;
|
|
if (domain) cookie += `; domain=${domain}`;
|
|
document.cookie = cookie;
|
|
}
|
|
|
|
export function readGuestCart(): CartItem[] {
|
|
if (typeof window === "undefined") return [];
|
|
const primary = parseItems(localStorage.getItem(MESHKEE_GUEST_CART_KEY));
|
|
if (primary.length > 0) return primary;
|
|
const legacy = parseItems(localStorage.getItem(LEGACY_GUEST_CART_KEY));
|
|
if (legacy.length > 0) {
|
|
writeGuestCart(legacy);
|
|
return legacy;
|
|
}
|
|
return [];
|
|
}
|
|
|
|
export function writeGuestCart(items: CartItem[]) {
|
|
if (typeof window === "undefined") return;
|
|
const raw = JSON.stringify(items);
|
|
localStorage.setItem(MESHKEE_GUEST_CART_KEY, raw);
|
|
localStorage.removeItem(LEGACY_GUEST_CART_KEY);
|
|
try {
|
|
writeSharedCookie(toMeshkeeGuestItems(items));
|
|
} catch {
|
|
// ignore cookie failures
|
|
}
|
|
}
|
|
|
|
export function clearGuestCart() {
|
|
if (typeof window === "undefined") return;
|
|
localStorage.removeItem(MESHKEE_GUEST_CART_KEY);
|
|
localStorage.removeItem(LEGACY_GUEST_CART_KEY);
|
|
const domain = cookieDomain();
|
|
let cookie = `${MESHKEE_GUEST_CART_KEY}=; path=/; max-age=0; SameSite=Lax`;
|
|
if (domain) cookie += `; domain=${domain}`;
|
|
document.cookie = cookie;
|
|
}
|