import type { GetAllProductsQuery, GetAllProductsQueryVariables, } from '../schema' import type { Product } from '@commerce/types' import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' import filterEdges from '../api/utils/filter-edges' import setProductLocaleMeta from '../api/utils/set-product-locale-meta' import { productConnectionFragment } from '../api/fragments/product' import { BigcommerceConfig, getConfig } from '../api' import { normalizeProduct } from '../lib/normalize' export const getAllProductsQuery = /* GraphQL */ ` query getAllProducts( $hasLocale: Boolean = false $locale: String = "null" $entityIds: [Int!] $first: Int = 10 $products: Boolean = false $featuredProducts: Boolean = false $bestSellingProducts: Boolean = false $newestProducts: Boolean = false ) { site { products(first: $first, entityIds: $entityIds) @include(if: $products) { ...productConnnection } featuredProducts(first: $first) @include(if: $featuredProducts) { ...productConnnection } bestSellingProducts(first: $first) @include(if: $bestSellingProducts) { ...productConnnection } newestProducts(first: $first) @include(if: $newestProducts) { ...productConnnection } } } ${productConnectionFragment} ` export type ProductEdge = NonNullable< NonNullable[0] > export type ProductNode = ProductEdge['node'] export type GetAllProductsResult< T extends Record = { products: ProductEdge[] } > = T const FIELDS = [ 'products', 'featuredProducts', 'bestSellingProducts', 'newestProducts', ] export type ProductTypes = | 'products' | 'featuredProducts' | 'bestSellingProducts' | 'newestProducts' export type ProductVariables = { field?: ProductTypes } & Omit< GetAllProductsQueryVariables, ProductTypes | 'hasLocale' > async function getAllProducts(opts?: { variables?: ProductVariables config?: BigcommerceConfig preview?: boolean }): Promise<{ products: Product[] }> async function getAllProducts< T extends Record, V = any >(opts: { query: string variables?: V config?: BigcommerceConfig preview?: boolean }): Promise> async function getAllProducts({ query = getAllProductsQuery, variables: { field = 'products', ...vars } = {}, config, }: { query?: string variables?: ProductVariables config?: BigcommerceConfig preview?: boolean // TODO: fix the product type here } = {}): Promise<{ products: Product[] | any[] }> { config = getConfig(config) const locale = vars.locale || config.locale const variables: GetAllProductsQueryVariables = { ...vars, locale, hasLocale: !!locale, } if (!FIELDS.includes(field)) { throw new Error( `The field variable has to match one of ${FIELDS.join(', ')}` ) } variables[field] = true // RecursivePartial forces the method to check for every prop in the data, which is // required in case there's a custom `query` const { data } = await config.fetch>( query, { variables } ) const edges = data.site?.[field]?.edges const products = filterEdges(edges as RecursiveRequired) if (locale && config.applyLocale) { products.forEach((product: RecursivePartial) => { if (product.node) setProductLocaleMeta(product.node) }) } return { products: products.map(({ node }) => normalizeProduct(node as any)) } } export default getAllProducts