import type { OperationContext, OperationOptions, } from '@commerce/api/operations' import type { GetAllProductsQuery, GetAllProductsQueryVariables, } from '../../schema' import type { GetAllProductsOperation } from '../../types/product' import type { RecursivePartial, RecursiveRequired } from '../utils/types' import filterEdges from '../utils/filter-edges' import setProductLocaleMeta from '../utils/set-product-locale-meta' import { productConnectionFragment } from '../fragments/product' import { BigcommerceConfig, Provider } from '..' 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 function getProductsType( relevance?: GetAllProductsOperation['variables']['relevance'] ) { switch (relevance) { case 'featured': return 'featuredProducts' case 'best_selling': return 'bestSellingProducts' case 'newest': return 'newestProducts' default: return 'products' } } export default function getAllProductsOperation({ commerce, }: OperationContext) { async function getAllProducts(opts?: { variables?: T['variables'] config?: Partial preview?: boolean }): Promise async function getAllProducts( opts: { variables?: T['variables'] config?: Partial preview?: boolean } & OperationOptions ): Promise async function getAllProducts({ query = getAllProductsQuery, variables: vars = {}, config: cfg, }: { query?: string variables?: T['variables'] config?: Partial preview?: boolean } = {}): Promise { const config = commerce.getConfig(cfg) const { locale } = config const field = getProductsType(vars.relevance) const variables: GetAllProductsQueryVariables = { locale, hasLocale: !!locale, } variables[field] = true if (vars.first) variables.first = vars.first if (vars.ids) variables.entityIds = vars.ids.map((id) => Number(id)) // 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)), } } return getAllProducts }