Vue Storefront is now Alokai! Learn More
AddCartLineItem

AddCartLineItem

Implements AddCartLineItem Unified Method.

Source

import type { AddCartLineItemArgs } from "@alokai/connect";
import { getNormalizers } from "@alokai/connect/integration-kit";
import { HttpStatusCode, ValidationError } from "@alokai/connect/middleware";
import type { Context } from "@vsf-enterprise/magento-api";
import { z } from "zod";

import { defineApi, query } from "@vsf-enterprise/unified-api-magento";
import { getCartId } from "@vsf-enterprise/unified-api-magento";
import { type Cart, isConfigurableProduct, type ProductWithTypeName } from "@vsf-enterprise/unified-api-magento/ecommerceTypes";

const addCartLineItemSchema = z.object({
  productId: z.string(),
  quantity: z.number().optional().default(1),
  sku: z.string(),
});

async function getCartItem(context: Context, args: AddCartLineItemArgs) {
  const { api } = await context.getApiClient();
  const productData = await query(
    api.productDetails({ filter: { sku: { eq: args.productId } }, pageSize: 1 }),
  );

  const selectedProduct = productData.products?.items?.[0] as ProductWithTypeName;
  if (!selectedProduct) {
    throw context.createHttpError({
      message: "Product not found",
      statusCode: HttpStatusCode.NOT_FOUND,
    });
  }
  if (isConfigurableProduct(selectedProduct)) {
    const variant = selectedProduct.variants
      ?.filter(Boolean)
      .find((productVariant) => productVariant.product?.sku === args.sku);
    if (!variant) {
      throw context.createHttpError({
        message: "Product not found",
        statusCode: HttpStatusCode.NOT_FOUND,
      });
    }
    const selected_options = (variant.attributes ?? [])
      ?.map((attribute) => attribute?.uid)
      .filter(Boolean);
    return { selected_options, sku: args.productId };
  }
  return { sku: args.sku as string };
}

export const addCartLineItem = defineApi.addCartLineItem(async (context, args) => {
  const { api } = await context.getApiClient();
  if (args?.cartId != null) {
    throw context.createHttpError({
      message: "Multiple carts feature is not available.",
      statusCode: HttpStatusCode.FORBIDDEN,
    });
  }

  const result = addCartLineItemSchema.safeParse(args);
  if (!result.success) {
    throw ValidationError.fromStandardSchemaError(result.error, "Missing required arguments");
  }
  const { productId, quantity, sku } = result.data;
  const cartItem = await getCartItem(context, { productId, sku });
  const cartId = getCartId(context);
  const { normalizeCart } = getNormalizers(context);

  const data = await query(
    api.addProductsToCart({
      cartId,
      cartItems: [{ quantity, ...cartItem }],
    }),
  );

  return normalizeCart(data?.addProductsToCart?.cart as Cart);
});