mirror of
https://github.com/vercel/commerce.git
synced 2025-06-19 13:41:22 +00:00
Updated getProduct operation
This commit is contained in:
parent
be5d47bac3
commit
a106629964
@ -23,6 +23,7 @@ import getSiteInfo from './operations/get-site-info'
|
|||||||
import getCustomerWishlist from './operations/get-customer-wishlist'
|
import getCustomerWishlist from './operations/get-customer-wishlist'
|
||||||
import getAllProductPaths from './operations/get-all-product-paths'
|
import getAllProductPaths from './operations/get-all-product-paths'
|
||||||
import getAllProducts from './operations/get-all-products'
|
import getAllProducts from './operations/get-all-products'
|
||||||
|
import getProduct from './operations/get-product'
|
||||||
|
|
||||||
export interface BigcommerceConfig extends CommerceAPIConfig {
|
export interface BigcommerceConfig extends CommerceAPIConfig {
|
||||||
// Indicates if the returned metadata with translations should be applied to the
|
// Indicates if the returned metadata with translations should be applied to the
|
||||||
@ -126,6 +127,7 @@ export const provider = {
|
|||||||
getCustomerWishlist,
|
getCustomerWishlist,
|
||||||
getAllProductPaths,
|
getAllProductPaths,
|
||||||
getAllProducts,
|
getAllProducts,
|
||||||
|
getProduct,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,27 +56,9 @@ export type GetAllProductsResult<
|
|||||||
}
|
}
|
||||||
> = T
|
> = T
|
||||||
|
|
||||||
const FIELDS = [
|
|
||||||
'products',
|
|
||||||
'featuredProducts',
|
|
||||||
'bestSellingProducts',
|
|
||||||
'newestProducts',
|
|
||||||
]
|
|
||||||
|
|
||||||
export type ProductTypes =
|
|
||||||
| 'products'
|
|
||||||
| 'featuredProducts'
|
|
||||||
| 'bestSellingProducts'
|
|
||||||
| 'newestProducts'
|
|
||||||
|
|
||||||
export type ProductVariables = { field?: ProductTypes } & Omit<
|
|
||||||
GetAllProductsQueryVariables,
|
|
||||||
ProductTypes | 'hasLocale'
|
|
||||||
>
|
|
||||||
|
|
||||||
function getProductsType(
|
function getProductsType(
|
||||||
relevance?: GetAllProductsOperation['variables']['relevance']
|
relevance?: GetAllProductsOperation['variables']['relevance']
|
||||||
): ProductTypes {
|
) {
|
||||||
switch (relevance) {
|
switch (relevance) {
|
||||||
case 'featured':
|
case 'featured':
|
||||||
return 'featuredProducts'
|
return 'featuredProducts'
|
||||||
@ -118,19 +100,13 @@ export default function getAllProductsOperation({
|
|||||||
} = {}): Promise<T['data']> {
|
} = {}): Promise<T['data']> {
|
||||||
config = commerce.getConfig(config)
|
config = commerce.getConfig(config)
|
||||||
|
|
||||||
const locale = config.locale
|
const { locale } = config
|
||||||
const field = getProductsType(vars.relevance)
|
const field = getProductsType(vars.relevance)
|
||||||
const variables: GetAllProductsQueryVariables = {
|
const variables: GetAllProductsQueryVariables = {
|
||||||
locale,
|
locale,
|
||||||
hasLocale: !!locale,
|
hasLocale: !!locale,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FIELDS.includes(field)) {
|
|
||||||
throw new Error(
|
|
||||||
`The field variable has to match one of ${FIELDS.join(', ')}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
variables[field] = true
|
variables[field] = true
|
||||||
|
|
||||||
if (vars.first) variables.first = vars.first
|
if (vars.first) variables.first = vars.first
|
||||||
|
120
framework/bigcommerce/api/operations/get-product.ts
Normal file
120
framework/bigcommerce/api/operations/get-product.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import type {
|
||||||
|
OperationContext,
|
||||||
|
OperationOptions,
|
||||||
|
} from '@commerce/api/operations'
|
||||||
|
import type { GetProductOperation } from '../../types/product'
|
||||||
|
import type { GetProductQuery, GetProductQueryVariables } from '../../schema'
|
||||||
|
import setProductLocaleMeta from '../utils/set-product-locale-meta'
|
||||||
|
import { productInfoFragment } from '../fragments/product'
|
||||||
|
import { BigcommerceConfig, Provider } from '..'
|
||||||
|
import { normalizeProduct } from '../../lib/normalize'
|
||||||
|
|
||||||
|
export const getProductQuery = /* GraphQL */ `
|
||||||
|
query getProduct(
|
||||||
|
$hasLocale: Boolean = false
|
||||||
|
$locale: String = "null"
|
||||||
|
$path: String!
|
||||||
|
) {
|
||||||
|
site {
|
||||||
|
route(path: $path) {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
... on Product {
|
||||||
|
...productInfo
|
||||||
|
variants {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
entityId
|
||||||
|
defaultImage {
|
||||||
|
urlOriginal
|
||||||
|
altText
|
||||||
|
isDefault
|
||||||
|
}
|
||||||
|
prices {
|
||||||
|
...productPrices
|
||||||
|
}
|
||||||
|
inventory {
|
||||||
|
aggregated {
|
||||||
|
availableToSell
|
||||||
|
warningLevel
|
||||||
|
}
|
||||||
|
isInStock
|
||||||
|
}
|
||||||
|
productOptions {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
entityId
|
||||||
|
displayName
|
||||||
|
...multipleChoiceOption
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
${productInfoFragment}
|
||||||
|
`
|
||||||
|
|
||||||
|
// TODO: See if this type is useful for defining the Product type
|
||||||
|
// export type ProductNode = Extract<
|
||||||
|
// GetProductQuery['site']['route']['node'],
|
||||||
|
// { __typename: 'Product' }
|
||||||
|
// >
|
||||||
|
|
||||||
|
export default function getAllProductPathsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getProduct<T extends GetProductOperation>(opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getProduct<T extends GetProductOperation>(
|
||||||
|
opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getProduct<T extends GetProductOperation>({
|
||||||
|
query = getProductQuery,
|
||||||
|
variables: { slug, ...vars },
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables: T['variables']
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']> {
|
||||||
|
config = commerce.getConfig(config)
|
||||||
|
|
||||||
|
const { locale } = config
|
||||||
|
const variables: GetProductQueryVariables = {
|
||||||
|
locale,
|
||||||
|
hasLocale: !!locale,
|
||||||
|
path: slug ? `/${slug}/` : vars.path!,
|
||||||
|
}
|
||||||
|
const { data } = await config.fetch<GetProductQuery>(query, { variables })
|
||||||
|
const product = data.site?.route?.node
|
||||||
|
|
||||||
|
if (product?.__typename === 'Product') {
|
||||||
|
if (locale && config.applyLocale) {
|
||||||
|
setProductLocaleMeta(product)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { product: normalizeProduct(product as any) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
return getProduct
|
||||||
|
}
|
@ -1,121 +0,0 @@
|
|||||||
import type { GetProductQuery, GetProductQueryVariables } from '../schema'
|
|
||||||
import setProductLocaleMeta from '../api/utils/set-product-locale-meta'
|
|
||||||
import { productInfoFragment } from '../api/fragments/product'
|
|
||||||
import { BigcommerceConfig, getConfig } from '../api'
|
|
||||||
import { normalizeProduct } from '../lib/normalize'
|
|
||||||
import type { Product } from '@commerce/types'
|
|
||||||
|
|
||||||
export const getProductQuery = /* GraphQL */ `
|
|
||||||
query getProduct(
|
|
||||||
$hasLocale: Boolean = false
|
|
||||||
$locale: String = "null"
|
|
||||||
$path: String!
|
|
||||||
) {
|
|
||||||
site {
|
|
||||||
route(path: $path) {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
... on Product {
|
|
||||||
...productInfo
|
|
||||||
variants {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
entityId
|
|
||||||
defaultImage {
|
|
||||||
urlOriginal
|
|
||||||
altText
|
|
||||||
isDefault
|
|
||||||
}
|
|
||||||
prices {
|
|
||||||
...productPrices
|
|
||||||
}
|
|
||||||
inventory {
|
|
||||||
aggregated {
|
|
||||||
availableToSell
|
|
||||||
warningLevel
|
|
||||||
}
|
|
||||||
isInStock
|
|
||||||
}
|
|
||||||
productOptions {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
__typename
|
|
||||||
entityId
|
|
||||||
displayName
|
|
||||||
...multipleChoiceOption
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
${productInfoFragment}
|
|
||||||
`
|
|
||||||
|
|
||||||
export type ProductNode = Extract<
|
|
||||||
GetProductQuery['site']['route']['node'],
|
|
||||||
{ __typename: 'Product' }
|
|
||||||
>
|
|
||||||
|
|
||||||
export type GetProductResult<
|
|
||||||
T extends { product?: any } = { product?: ProductNode }
|
|
||||||
> = T
|
|
||||||
|
|
||||||
export type ProductVariables = { locale?: string } & (
|
|
||||||
| { path: string; slug?: never }
|
|
||||||
| { path?: never; slug: string }
|
|
||||||
)
|
|
||||||
|
|
||||||
async function getProduct(opts: {
|
|
||||||
variables: ProductVariables
|
|
||||||
config?: BigcommerceConfig
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<GetProductResult>
|
|
||||||
|
|
||||||
async function getProduct<T extends { product?: any }, V = any>(opts: {
|
|
||||||
query: string
|
|
||||||
variables: V
|
|
||||||
config?: BigcommerceConfig
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<GetProductResult<T>>
|
|
||||||
|
|
||||||
async function getProduct({
|
|
||||||
query = getProductQuery,
|
|
||||||
variables: { slug, ...vars },
|
|
||||||
config,
|
|
||||||
}: {
|
|
||||||
query?: string
|
|
||||||
variables: ProductVariables
|
|
||||||
config?: BigcommerceConfig
|
|
||||||
preview?: boolean
|
|
||||||
}): Promise<Product | {} | any> {
|
|
||||||
config = getConfig(config)
|
|
||||||
|
|
||||||
const locale = vars.locale || config.locale
|
|
||||||
const variables: GetProductQueryVariables = {
|
|
||||||
...vars,
|
|
||||||
locale,
|
|
||||||
hasLocale: !!locale,
|
|
||||||
path: slug ? `/${slug}/` : vars.path!,
|
|
||||||
}
|
|
||||||
const { data } = await config.fetch<GetProductQuery>(query, { variables })
|
|
||||||
const product = data.site?.route?.node
|
|
||||||
|
|
||||||
if (product?.__typename === 'Product') {
|
|
||||||
if (locale && config.applyLocale) {
|
|
||||||
setProductLocaleMeta(product)
|
|
||||||
}
|
|
||||||
|
|
||||||
return { product: normalizeProduct(product as any) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getProduct
|
|
@ -1,4 +1,2 @@
|
|||||||
export { default as usePrice } from './use-price'
|
export { default as usePrice } from './use-price'
|
||||||
export { default as useSearch } from './use-search'
|
export { default as useSearch } from './use-search'
|
||||||
export { default as getProduct } from './get-product'
|
|
||||||
export { default as getAllProducts } from '../api/operations/get-all-products'
|
|
||||||
|
@ -6,6 +6,7 @@ import type { GetCustomerWishlistOperation } from '../types/wishlist'
|
|||||||
import type {
|
import type {
|
||||||
GetAllProductPathsOperation,
|
GetAllProductPathsOperation,
|
||||||
GetAllProductsOperation,
|
GetAllProductsOperation,
|
||||||
|
GetProductOperation,
|
||||||
} from '../types/product'
|
} from '../types/product'
|
||||||
import type { APIProvider, CommerceAPI } from '.'
|
import type { APIProvider, CommerceAPI } from '.'
|
||||||
|
|
||||||
@ -128,6 +129,22 @@ export type Operations<P extends APIProvider> = {
|
|||||||
} & OperationOptions
|
} & OperationOptions
|
||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProduct: {
|
||||||
|
<T extends GetProductOperation>(opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetProductOperation>(
|
||||||
|
opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type APIOperations<P extends APIProvider> = {
|
export type APIOperations<P extends APIProvider> = {
|
||||||
|
@ -81,3 +81,8 @@ export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
|||||||
first?: number
|
first?: number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetProductOperation<T extends ProductTypes = ProductTypes> = {
|
||||||
|
data: { product?: T['product'] }
|
||||||
|
variables: { path: string; slug?: never } | { path?: never; slug: string }
|
||||||
|
}
|
||||||
|
@ -7,9 +7,7 @@ import { useRouter } from 'next/router'
|
|||||||
import commerce from '@lib/api/commerce'
|
import commerce from '@lib/api/commerce'
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { ProductView } from '@components/product'
|
import { ProductView } from '@components/product'
|
||||||
|
|
||||||
import { getConfig } from '@framework/api'
|
import { getConfig } from '@framework/api'
|
||||||
import getProduct from '@framework/product/get-product'
|
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({
|
||||||
params,
|
params,
|
||||||
@ -18,7 +16,7 @@ export async function getStaticProps({
|
|||||||
}: GetStaticPropsContext<{ slug: string }>) {
|
}: GetStaticPropsContext<{ slug: string }>) {
|
||||||
const config = getConfig({ locale })
|
const config = getConfig({ locale })
|
||||||
const { pages } = await commerce.getAllPages({ config, preview })
|
const { pages } = await commerce.getAllPages({ config, preview })
|
||||||
const { product } = await getProduct({
|
const { product } = await commerce.getProduct({
|
||||||
variables: { slug: params!.slug },
|
variables: { slug: params!.slug },
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user