Vue Storefront is now Alokai! Learn More
SearchProducts

SearchProducts

Implements SearchProducts Unified Method.

Source

import { InternalContext, getNormalizerContext, defineApi } from "@vsf-enterprise/unified-api-bigcommerce";
import { GraphQL, ProductsResponse } from "@vsf-enterprise/bigcommerce-api";
import { getNormalizers } from "@vue-storefront/unified-data-model";
import { NormalizedRequestArgs, getBuilders, normalizeRequestParams } from "./helpers";

export const searchProducts = defineApi.searchProducts(async (context, args) => {
  const { normalizeProductCatalogItem } = getNormalizers(context);
  const normalizedParams = await normalizeRequestParams(context, args);
  const [productsResponse, filtersResponse] = await Promise.all([
    getProductsWithFilter(context, normalizedParams),
    getFilters(context, normalizedParams),
  ]);

  const products = productsResponse.data.map((product) =>
    normalizeProductCatalogItem(product, getNormalizerContext(context)),
  );

  const { buildFacets, buildPagination } = getBuilders(context);

  return {
    products,
    ...buildFacets(filtersResponse, context),
    ...buildPagination(productsResponse, normalizedParams),
  };
});

async function getProductsWithFilter(
  context: InternalContext,
  args: NormalizedRequestArgs,
): Promise<ProductsResponse> {
  const { currentPage, categoryEntityId, searchTerm, productAttributes, pageSize, sort } = args;
  let products: ProductsResponse;

  products = await context.api.getProductsWithFilter({
    filters: {
      categoryEntityId,
      searchTerm,
      productAttributes,
    },
    currencyCode: getNormalizerContext(context).currency as GraphQL.CurrencyCode,
    // API does not support offset pagination, so we have to fetch all products and then slice them
    first: pageSize * currentPage,
    sort,
  });

  products = {
    ...products,
    data: products.data.slice(-pageSize),
  };

  return products;
}

async function getFilters(
  context: InternalContext,
  args: NormalizedRequestArgs,
): Promise<GraphQL.SearchProductFilterConnection> {
  const { categoryEntityId, searchTerm, productAttributes } = args;
  try {
    return await context.api.getFilters({
      filters: {
        categoryEntityId,
        searchTerm,
        productAttributes,
      },
    });
  } catch {
    return {} as any;
  }
}