import { AddProductToCartDocument, ClearCartDocument, MyCartDocument, RemoveCartItemDocument, SetCartDeliveryAddressDocument, UpdateCartItemQuantityDocument, type MyCartQuery, } from '~/composables/graphql/generated'; import { useGqlClient } from '~/composables/useGqlClient'; type CartParameters = { width: number; thickness: number; color: string; }; export type ClientCartItem = { productId: string; productName: string; sku: string; isCustomizable: boolean; quantity: number; parameters: CartParameters; }; function normalizeQuantity(value: number) { if (!Number.isFinite(value) || value < 0) { return 0; } return Math.floor(value); } function normalizeParameters(value: unknown): CartParameters { const source = (value && typeof value === 'object') ? value as Partial : {}; return { width: Number(source.width ?? 100), thickness: Number(source.thickness ?? 50), color: typeof source.color === 'string' ? source.color : 'прозрачный', }; } function mapCartItem(item: MyCartQuery['myCart']['items'][number]): ClientCartItem { return { productId: item.productId, productName: item.productName, sku: item.sku, isCustomizable: item.isCustomizable, quantity: Number(item.quantity), parameters: normalizeParameters(item.parameters), }; } export function useClientCart() { const client = useGqlClient(); const items = useState('client-cart-items', () => []); const selectedDeliveryAddressId = useState('client-cart-delivery-address-id', () => ''); const initialized = useState('client-cart-initialized', () => false); const loading = useState('client-cart-loading', () => false); const totalPositions = computed(() => items.value.length); const totalItems = computed(() => items.value.reduce((sum, item) => sum + item.quantity, 0)); const totalVolume = computed(() => items.value.reduce((sum, item) => sum + item.quantity * item.parameters.width * item.parameters.thickness, 0), ); function applyCart(cart: MyCartQuery['myCart']) { items.value = cart.items.map(mapCartItem); selectedDeliveryAddressId.value = cart.deliveryAddressId ?? ''; initialized.value = true; } async function fetchCart(force = false) { if (loading.value) { return; } if (initialized.value && !force) { return; } loading.value = true; try { const { data } = await client.query({ query: MyCartDocument, fetchPolicy: 'network-only', }); if (data?.myCart) { applyCart(data.myCart); } } finally { loading.value = false; } } function getQuantity(productId: string) { return items.value.find((item) => item.productId === productId)?.quantity ?? 0; } async function addProduct(product: { id: string; name: string; sku: string; isCustomizable: boolean; }) { const { data } = await client.mutate({ mutation: AddProductToCartDocument, variables: { productId: product.id }, fetchPolicy: 'no-cache', }); if (data?.addProductToCart) { applyCart(data.addProductToCart); } } async function setQuantity(productId: string, quantity: number) { const normalizedQuantity = normalizeQuantity(quantity); const { data } = await client.mutate({ mutation: UpdateCartItemQuantityDocument, variables: { input: { productId, quantity: normalizedQuantity, }, }, fetchPolicy: 'no-cache', }); if (data?.updateCartItemQuantity) { applyCart(data.updateCartItemQuantity); } } async function incrementQuantity(productId: string) { await setQuantity(productId, getQuantity(productId) + 1); } async function decrementQuantity(productId: string) { await setQuantity(productId, getQuantity(productId) - 1); } async function removeProduct(productId: string) { const { data } = await client.mutate({ mutation: RemoveCartItemDocument, variables: { productId }, fetchPolicy: 'no-cache', }); if (data?.removeCartItem) { applyCart(data.removeCartItem); } } async function setDeliveryAddress(addressId: string | null) { const { data } = await client.mutate({ mutation: SetCartDeliveryAddressDocument, variables: { addressId: addressId || null }, fetchPolicy: 'no-cache', }); if (data?.setCartDeliveryAddress) { applyCart(data.setCartDeliveryAddress); } } async function clearCart() { const { data } = await client.mutate({ mutation: ClearCartDocument, fetchPolicy: 'no-cache', }); if (data?.clearCart) { applyCart(data.clearCart); } } if (!initialized.value && !loading.value) { void fetchCart(); } return { items, loading, selectedDeliveryAddressId, totalPositions, totalItems, totalVolume, fetchCart, addProduct, setQuantity, incrementQuantity, decrementQuantity, removeProduct, clearCart, setDeliveryAddress, getQuantity, }; }