mirror of
https://github.com/vercel/commerce.git
synced 2025-06-20 06:01:21 +00:00
Add Shopify related products
This commit is contained in:
parent
74dda1aa55
commit
396a708e23
@ -61,6 +61,7 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
|
|||||||
<ProductSidebar product={product} className={s.sidebar} />
|
<ProductSidebar product={product} className={s.sidebar} />
|
||||||
</div>
|
</div>
|
||||||
<hr className="mt-7 border-accent-2" />
|
<hr className="mt-7 border-accent-2" />
|
||||||
|
{relatedProducts.length && (
|
||||||
<section className="py-12 px-6 mb-10">
|
<section className="py-12 px-6 mb-10">
|
||||||
<Text variant="sectionHeading">Related Products</Text>
|
<Text variant="sectionHeading">Related Products</Text>
|
||||||
<div className={s.relatedProductsGrid}>
|
<div className={s.relatedProductsGrid}>
|
||||||
@ -84,6 +85,7 @@ const ProductView: FC<ProductViewProps> = ({ product, relatedProducts }) => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
)}
|
||||||
</Container>
|
</Container>
|
||||||
<NextSeo
|
<NextSeo
|
||||||
title={product.name}
|
title={product.name}
|
||||||
|
@ -7,10 +7,11 @@ import type {
|
|||||||
GetAllProductPathsOperation,
|
GetAllProductPathsOperation,
|
||||||
GetAllProductsOperation,
|
GetAllProductsOperation,
|
||||||
GetProductOperation,
|
GetProductOperation,
|
||||||
|
GetRelatedProductsOperation,
|
||||||
} from '../types/product'
|
} from '../types/product'
|
||||||
import type { APIProvider, CommerceAPI } from '.'
|
import type { APIProvider, CommerceAPI } from '.'
|
||||||
|
|
||||||
const noop = () => {
|
const noop = (_props?: any) => {
|
||||||
throw new Error('Not implemented')
|
throw new Error('Not implemented')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ export const OPERATIONS = [
|
|||||||
'getCustomerWishlist',
|
'getCustomerWishlist',
|
||||||
'getAllProductPaths',
|
'getAllProductPaths',
|
||||||
'getAllProducts',
|
'getAllProducts',
|
||||||
|
'getRelatedProducts',
|
||||||
'getProduct',
|
'getProduct',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
@ -139,6 +141,22 @@ export type Operations<P extends APIProvider> = {
|
|||||||
): Promise<T['data']>
|
): Promise<T['data']>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRelatedProducts: {
|
||||||
|
<T extends GetRelatedProductsOperation>(opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
<T extends GetAllProductsOperation>(
|
||||||
|
opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: P['config']
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
}
|
||||||
|
|
||||||
getProduct: {
|
getProduct: {
|
||||||
<T extends GetProductOperation>(opts: {
|
<T extends GetProductOperation>(opts: {
|
||||||
variables: T['variables']
|
variables: T['variables']
|
||||||
|
@ -93,6 +93,16 @@ export type GetAllProductsOperation<T extends ProductTypes = ProductTypes> = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetRelatedProductsOperation<
|
||||||
|
T extends ProductTypes = ProductTypes
|
||||||
|
> = {
|
||||||
|
data: { products: T['product'][] }
|
||||||
|
variables: {
|
||||||
|
productId: string
|
||||||
|
first?: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export type GetProductOperation<T extends ProductTypes = ProductTypes> = {
|
export type GetProductOperation<T extends ProductTypes = ProductTypes> = {
|
||||||
data: { product?: T['product'] }
|
data: { product?: T['product'] }
|
||||||
variables: { path: string; slug?: never } | { path?: never; slug: string }
|
variables: { path: string; slug?: never } | { path?: never; slug: string }
|
||||||
|
74
framework/shopify/api/operations/get-related-products.ts
Normal file
74
framework/shopify/api/operations/get-related-products.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import type {
|
||||||
|
OperationContext,
|
||||||
|
OperationOptions,
|
||||||
|
} from '@commerce/api/operations'
|
||||||
|
import { GetRelatedProductsOperation } from '../../types/product'
|
||||||
|
import {
|
||||||
|
GetRelatedProductsQuery,
|
||||||
|
GetRelatedProductsQueryVariables,
|
||||||
|
Product as ShopifyProduct,
|
||||||
|
} from '../../schema'
|
||||||
|
import type { ShopifyConfig, Provider } from '..'
|
||||||
|
import getRelatedProductsQuery from '../../utils/queries/get-related-products-query'
|
||||||
|
import { normalizeProduct } from '../../utils'
|
||||||
|
|
||||||
|
export default function getRelatedProductsOperation({
|
||||||
|
commerce,
|
||||||
|
}: OperationContext<Provider>) {
|
||||||
|
async function getRelatedProductsOperation<
|
||||||
|
T extends GetRelatedProductsOperation
|
||||||
|
>(opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: Partial<ShopifyConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getRelatedProductsOperation<
|
||||||
|
T extends GetRelatedProductsOperation
|
||||||
|
>(
|
||||||
|
opts: {
|
||||||
|
variables: T['variables']
|
||||||
|
config?: Partial<ShopifyConfig>
|
||||||
|
preview?: boolean
|
||||||
|
} & OperationOptions
|
||||||
|
): Promise<T['data']>
|
||||||
|
|
||||||
|
async function getRelatedProductsOperation<
|
||||||
|
T extends GetRelatedProductsOperation
|
||||||
|
>({
|
||||||
|
query = getRelatedProductsQuery,
|
||||||
|
variables,
|
||||||
|
config,
|
||||||
|
}: {
|
||||||
|
query?: string
|
||||||
|
variables: T['variables']
|
||||||
|
config?: Partial<ShopifyConfig>
|
||||||
|
preview?: boolean
|
||||||
|
}): Promise<T['data']> {
|
||||||
|
const { fetch, locale } = commerce.getConfig(config)
|
||||||
|
|
||||||
|
const { data } = await fetch<
|
||||||
|
GetRelatedProductsQuery,
|
||||||
|
GetRelatedProductsQueryVariables
|
||||||
|
>(
|
||||||
|
query,
|
||||||
|
{ variables },
|
||||||
|
{
|
||||||
|
...(locale && {
|
||||||
|
headers: {
|
||||||
|
'Accept-Language': locale,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
products:
|
||||||
|
data.productRecommendations
|
||||||
|
?.map((product) => normalizeProduct(product as ShopifyProduct))
|
||||||
|
.splice(0, variables?.first || 4) ?? [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRelatedProductsOperation
|
||||||
|
}
|
@ -2,6 +2,7 @@ export { default as getAllPages } from './get-all-pages'
|
|||||||
export { default as getPage } from './get-page'
|
export { default as getPage } from './get-page'
|
||||||
export { default as getAllProducts } from './get-all-products'
|
export { default as getAllProducts } from './get-all-products'
|
||||||
export { default as getAllProductPaths } from './get-all-product-paths'
|
export { default as getAllProductPaths } from './get-all-product-paths'
|
||||||
|
export { default as getRelatedProducts } from './get-related-products'
|
||||||
export { default as getProduct } from './get-product'
|
export { default as getProduct } from './get-product'
|
||||||
export { default as getSiteInfo } from './get-site-info'
|
export { default as getSiteInfo } from './get-site-info'
|
||||||
export { default as login } from './login'
|
export { default as login } from './login'
|
||||||
|
57
framework/shopify/schema.d.ts
vendored
57
framework/shopify/schema.d.ts
vendored
@ -2635,7 +2635,7 @@ export type FulfillmentTrackingInfo = {
|
|||||||
|
|
||||||
/** Represents information about the metafields associated to the specified resource. */
|
/** Represents information about the metafields associated to the specified resource. */
|
||||||
export type HasMetafields = {
|
export type HasMetafields = {
|
||||||
/** The metafield associated with the resource. */
|
/** Returns a metafield found by namespace and key. */
|
||||||
metafield?: Maybe<Metafield>
|
metafield?: Maybe<Metafield>
|
||||||
/** A paginated list of metafields associated with the resource. */
|
/** A paginated list of metafields associated with the resource. */
|
||||||
metafields: MetafieldConnection
|
metafields: MetafieldConnection
|
||||||
@ -3908,7 +3908,7 @@ export type Product = Node &
|
|||||||
images: ImageConnection
|
images: ImageConnection
|
||||||
/** The media associated with the product. */
|
/** The media associated with the product. */
|
||||||
media: MediaConnection
|
media: MediaConnection
|
||||||
/** The metafield associated with the resource. */
|
/** Returns a metafield found by namespace and key. */
|
||||||
metafield?: Maybe<Metafield>
|
metafield?: Maybe<Metafield>
|
||||||
/** A paginated list of metafields associated with the resource. */
|
/** A paginated list of metafields associated with the resource. */
|
||||||
metafields: MetafieldConnection
|
metafields: MetafieldConnection
|
||||||
@ -4235,7 +4235,7 @@ export type ProductVariant = Node &
|
|||||||
id: Scalars['ID']
|
id: Scalars['ID']
|
||||||
/** Image associated with the product variant. This field falls back to the product image if no image is available. */
|
/** Image associated with the product variant. This field falls back to the product image if no image is available. */
|
||||||
image?: Maybe<Image>
|
image?: Maybe<Image>
|
||||||
/** The metafield associated with the resource. */
|
/** Returns a metafield found by namespace and key. */
|
||||||
metafield?: Maybe<Metafield>
|
metafield?: Maybe<Metafield>
|
||||||
/** A paginated list of metafields associated with the resource. */
|
/** A paginated list of metafields associated with the resource. */
|
||||||
metafields: MetafieldConnection
|
metafields: MetafieldConnection
|
||||||
@ -5265,14 +5265,7 @@ export type GetAllProductPathsQuery = { __typename?: 'QueryRoot' } & {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProductConnectionFragment = { __typename?: 'ProductConnection' } & {
|
export type ListProductDetailsFragment = { __typename?: 'Product' } & Pick<
|
||||||
pageInfo: { __typename?: 'PageInfo' } & Pick<
|
|
||||||
PageInfo,
|
|
||||||
'hasNextPage' | 'hasPreviousPage'
|
|
||||||
>
|
|
||||||
edges: Array<
|
|
||||||
{ __typename?: 'ProductEdge' } & {
|
|
||||||
node: { __typename?: 'Product' } & Pick<
|
|
||||||
Product,
|
Product,
|
||||||
'id' | 'title' | 'vendor' | 'handle'
|
'id' | 'title' | 'vendor' | 'handle'
|
||||||
> & {
|
> & {
|
||||||
@ -5297,6 +5290,15 @@ export type ProductConnectionFragment = { __typename?: 'ProductConnection' } & {
|
|||||||
>
|
>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ProductConnectionFragment = { __typename?: 'ProductConnection' } & {
|
||||||
|
pageInfo: { __typename?: 'PageInfo' } & Pick<
|
||||||
|
PageInfo,
|
||||||
|
'hasNextPage' | 'hasPreviousPage'
|
||||||
|
>
|
||||||
|
edges: Array<
|
||||||
|
{ __typename?: 'ProductEdge' } & {
|
||||||
|
node: { __typename?: 'Product' } & ListProductDetailsFragment
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
@ -5344,6 +5346,12 @@ export type CheckoutDetailsFragment = { __typename?: 'Checkout' } & Pick<
|
|||||||
ProductVariant,
|
ProductVariant,
|
||||||
'id' | 'sku' | 'title'
|
'id' | 'sku' | 'title'
|
||||||
> & {
|
> & {
|
||||||
|
selectedOptions: Array<
|
||||||
|
{ __typename?: 'SelectedOption' } & Pick<
|
||||||
|
SelectedOption,
|
||||||
|
'name' | 'value'
|
||||||
|
>
|
||||||
|
>
|
||||||
image?: Maybe<
|
image?: Maybe<
|
||||||
{ __typename?: 'Image' } & Pick<
|
{ __typename?: 'Image' } & Pick<
|
||||||
Image,
|
Image,
|
||||||
@ -5498,16 +5506,11 @@ export type GetPageQuery = { __typename?: 'QueryRoot' } & {
|
|||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GetProductBySlugQueryVariables = Exact<{
|
export type ProductDetailsFragment = { __typename?: 'Product' } & Pick<
|
||||||
slug: Scalars['String']
|
|
||||||
}>
|
|
||||||
|
|
||||||
export type GetProductBySlugQuery = { __typename?: 'QueryRoot' } & {
|
|
||||||
productByHandle?: Maybe<
|
|
||||||
{ __typename?: 'Product' } & Pick<
|
|
||||||
Product,
|
Product,
|
||||||
| 'id'
|
| 'id'
|
||||||
| 'handle'
|
| 'handle'
|
||||||
|
| 'availableForSale'
|
||||||
| 'title'
|
| 'title'
|
||||||
| 'productType'
|
| 'productType'
|
||||||
| 'vendor'
|
| 'vendor'
|
||||||
@ -5539,7 +5542,7 @@ export type GetProductBySlugQuery = { __typename?: 'QueryRoot' } & {
|
|||||||
{ __typename?: 'ProductVariantEdge' } & {
|
{ __typename?: 'ProductVariantEdge' } & {
|
||||||
node: { __typename?: 'ProductVariant' } & Pick<
|
node: { __typename?: 'ProductVariant' } & Pick<
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
'id' | 'title' | 'sku'
|
'id' | 'title' | 'sku' | 'availableForSale' | 'requiresShipping'
|
||||||
> & {
|
> & {
|
||||||
selectedOptions: Array<
|
selectedOptions: Array<
|
||||||
{ __typename?: 'SelectedOption' } & Pick<
|
{ __typename?: 'SelectedOption' } & Pick<
|
||||||
@ -5576,6 +5579,22 @@ export type GetProductBySlugQuery = { __typename?: 'QueryRoot' } & {
|
|||||||
>
|
>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetProductBySlugQueryVariables = Exact<{
|
||||||
|
slug: Scalars['String']
|
||||||
|
}>
|
||||||
|
|
||||||
|
export type GetProductBySlugQuery = { __typename?: 'QueryRoot' } & {
|
||||||
|
productByHandle?: Maybe<{ __typename?: 'Product' } & ProductDetailsFragment>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GetRelatedProductsQueryVariables = Exact<{
|
||||||
|
productId: Scalars['ID']
|
||||||
|
}>
|
||||||
|
|
||||||
|
export type GetRelatedProductsQuery = { __typename?: 'QueryRoot' } & {
|
||||||
|
productRecommendations?: Maybe<
|
||||||
|
Array<{ __typename?: 'Product' } & ListProductDetailsFragment>
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,16 +13,6 @@ directive @accessRestricted(
|
|||||||
reason: String = null
|
reason: String = null
|
||||||
) on FIELD_DEFINITION | OBJECT
|
) on FIELD_DEFINITION | OBJECT
|
||||||
|
|
||||||
"""
|
|
||||||
Contextualize data.
|
|
||||||
"""
|
|
||||||
directive @inContext(
|
|
||||||
"""
|
|
||||||
The country code for context.
|
|
||||||
"""
|
|
||||||
country: CountryCode!
|
|
||||||
) on QUERY | MUTATION
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A version of the API.
|
A version of the API.
|
||||||
"""
|
"""
|
||||||
@ -829,7 +819,7 @@ input CheckoutAttributesUpdateInput {
|
|||||||
The required attributes are city, province, and country.
|
The required attributes are city, province, and country.
|
||||||
Full validation of the addresses is still done at complete time.
|
Full validation of the addresses is still done at complete time.
|
||||||
"""
|
"""
|
||||||
allowPartialAddresses: Boolean
|
allowPartialAddresses: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -872,7 +862,7 @@ input CheckoutAttributesUpdateV2Input {
|
|||||||
The required attributes are city, province, and country.
|
The required attributes are city, province, and country.
|
||||||
Full validation of the addresses is still done at complete time.
|
Full validation of the addresses is still done at complete time.
|
||||||
"""
|
"""
|
||||||
allowPartialAddresses: Boolean
|
allowPartialAddresses: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -3391,7 +3381,7 @@ input CreditCardPaymentInput {
|
|||||||
"""
|
"""
|
||||||
Executes the payment in test mode if possible. Defaults to `false`.
|
Executes the payment in test mode if possible. Defaults to `false`.
|
||||||
"""
|
"""
|
||||||
test: Boolean
|
test: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -3422,7 +3412,7 @@ input CreditCardPaymentInputV2 {
|
|||||||
"""
|
"""
|
||||||
Executes the payment in test mode if possible. Defaults to `false`.
|
Executes the payment in test mode if possible. Defaults to `false`.
|
||||||
"""
|
"""
|
||||||
test: Boolean
|
test: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -5325,7 +5315,7 @@ Represents information about the metafields associated to the specified resource
|
|||||||
"""
|
"""
|
||||||
interface HasMetafields {
|
interface HasMetafields {
|
||||||
"""
|
"""
|
||||||
The metafield associated with the resource.
|
Returns a metafield found by namespace and key.
|
||||||
"""
|
"""
|
||||||
metafield(
|
metafield(
|
||||||
"""
|
"""
|
||||||
@ -7648,7 +7638,7 @@ type Product implements Node & HasMetafields {
|
|||||||
): MediaConnection!
|
): MediaConnection!
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The metafield associated with the resource.
|
Returns a metafield found by namespace and key.
|
||||||
"""
|
"""
|
||||||
metafield(
|
metafield(
|
||||||
"""
|
"""
|
||||||
@ -8150,7 +8140,7 @@ type ProductVariant implements Node & HasMetafields {
|
|||||||
): Image
|
): Image
|
||||||
|
|
||||||
"""
|
"""
|
||||||
The metafield associated with the resource.
|
Returns a metafield found by namespace and key.
|
||||||
"""
|
"""
|
||||||
metafield(
|
metafield(
|
||||||
"""
|
"""
|
||||||
@ -9298,7 +9288,7 @@ input TokenizedPaymentInput {
|
|||||||
"""
|
"""
|
||||||
Executes the payment in test mode if possible. Defaults to `false`.
|
Executes the payment in test mode if possible. Defaults to `false`.
|
||||||
"""
|
"""
|
||||||
test: Boolean
|
test: Boolean = false
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Public Hash Key used for AndroidPay payments only.
|
Public Hash Key used for AndroidPay payments only.
|
||||||
@ -9334,7 +9324,7 @@ input TokenizedPaymentInputV2 {
|
|||||||
"""
|
"""
|
||||||
Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`.
|
Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`.
|
||||||
"""
|
"""
|
||||||
test: Boolean
|
test: Boolean = false
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Public Hash Key used for AndroidPay payments only.
|
Public Hash Key used for AndroidPay payments only.
|
||||||
@ -9375,7 +9365,7 @@ input TokenizedPaymentInputV3 {
|
|||||||
"""
|
"""
|
||||||
Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`.
|
Whether to execute the payment in test mode, if possible. Test mode is not supported in production stores. Defaults to `false`.
|
||||||
"""
|
"""
|
||||||
test: Boolean
|
test: Boolean = false
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Public Hash Key used for AndroidPay payments only.
|
Public Hash Key used for AndroidPay payments only.
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
export const productConnectionFragment = /* GraphQL */ `
|
export const listProductDetailsFragment = /* GraphQL */ `
|
||||||
fragment productConnection on ProductConnection {
|
fragment listProductDetails on Product {
|
||||||
pageInfo {
|
|
||||||
hasNextPage
|
|
||||||
hasPreviousPage
|
|
||||||
}
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
vendor
|
vendor
|
||||||
@ -31,8 +25,21 @@ export const productConnectionFragment = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const productConnectionFragment = /* GraphQL */ `
|
||||||
|
fragment productConnection on ProductConnection {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
hasPreviousPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...listProductDetails
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
${listProductDetailsFragment}
|
||||||
`
|
`
|
||||||
|
|
||||||
const getAllProductsQuery = /* GraphQL */ `
|
const getAllProductsQuery = /* GraphQL */ `
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const getProductQuery = /* GraphQL */ `
|
export const productDetailsFragment = /* GraphQL */ `
|
||||||
query getProductBySlug($slug: String!) {
|
fragment productDetails on Product {
|
||||||
productByHandle(handle: $slug) {
|
|
||||||
id
|
id
|
||||||
handle
|
handle
|
||||||
availableForSale
|
availableForSale
|
||||||
@ -66,7 +65,15 @@ const getProductQuery = /* GraphQL */ `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const getProductQuery = /* GraphQL */ `
|
||||||
|
query getProductBySlug($slug: String!) {
|
||||||
|
productByHandle(handle: $slug) {
|
||||||
|
...productDetails
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
${productDetailsFragment}
|
||||||
`
|
`
|
||||||
|
|
||||||
export default getProductQuery
|
export default getProductQuery
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import { listProductDetailsFragment } from './get-all-products-query'
|
||||||
|
|
||||||
|
const getRelatedProductsQuery = /* GraphQL */ `
|
||||||
|
query getRelatedProducts($productId: ID!) {
|
||||||
|
productRecommendations(productId: $productId) {
|
||||||
|
...listProductDetails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${listProductDetailsFragment}
|
||||||
|
`
|
||||||
|
export default getRelatedProductsQuery
|
@ -28,15 +28,27 @@ export async function getStaticProps({
|
|||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
})
|
})
|
||||||
|
|
||||||
const { pages } = await pagesPromise
|
const { pages } = await pagesPromise
|
||||||
const { categories } = await siteInfoPromise
|
const { categories } = await siteInfoPromise
|
||||||
const { product } = await productPromise
|
const { product } = await productPromise
|
||||||
const { products: relatedProducts } = await allProductsPromise
|
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
throw new Error(`Product with slug '${params!.slug}' not found`)
|
throw new Error(`Product with slug '${params!.slug}' not found`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const relatedProductsPromise = commerce.getRelatedProducts({
|
||||||
|
variables: { productId: product.id, first: 4 },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Temporary conditional query
|
||||||
|
const { products: relatedProducts } =
|
||||||
|
process.env.COMMERCE_PROVIDER === 'shopify'
|
||||||
|
? await relatedProductsPromise
|
||||||
|
: await allProductsPromise
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
pages,
|
pages,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user