Added locale metadata for products and product page
This commit is contained in:
		@@ -78,6 +78,15 @@ export const productInfoFragment = /* GraphQL */ `
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    localeMeta: metafields(namespace: $locale, keys: ["name", "description"])
 | 
			
		||||
      @include(if: $hasLocale) {
 | 
			
		||||
      edges {
 | 
			
		||||
        node {
 | 
			
		||||
          key
 | 
			
		||||
          value
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ${responsiveImageFragment}
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,9 @@ export type ProductImageVariables = Pick<
 | 
			
		||||
>
 | 
			
		||||
 | 
			
		||||
export interface BigcommerceConfigOptions extends CommerceAPIConfig {
 | 
			
		||||
  // Indicates if the returned metadata with translations should be applied to the
 | 
			
		||||
  // data or returned as it is
 | 
			
		||||
  applyLocale?: boolean
 | 
			
		||||
  images?: Images
 | 
			
		||||
  storeApiUrl: string
 | 
			
		||||
  storeApiToken: string
 | 
			
		||||
@@ -113,6 +116,7 @@ const config = new Config({
 | 
			
		||||
  cartCookie: process.env.BIGCOMMERCE_CART_COOKIE ?? 'bc_cartId',
 | 
			
		||||
  cartCookieMaxAge: ONE_DAY * 30,
 | 
			
		||||
  fetch: fetchGraphqlApi,
 | 
			
		||||
  applyLocale: true,
 | 
			
		||||
  // REST API only
 | 
			
		||||
  storeApiUrl: STORE_API_URL,
 | 
			
		||||
  storeApiToken: STORE_API_TOKEN,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,14 @@ import type {
 | 
			
		||||
} from '@lib/bigcommerce/schema'
 | 
			
		||||
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, getConfig, Images, ProductImageVariables } from '..'
 | 
			
		||||
 | 
			
		||||
export const getAllProductsQuery = /* GraphQL */ `
 | 
			
		||||
  query getAllProducts(
 | 
			
		||||
    $hasLocale: Boolean = false
 | 
			
		||||
    $locale: String = "null"
 | 
			
		||||
    $entityIds: [Int!]
 | 
			
		||||
    $first: Int = 10
 | 
			
		||||
    $imgSmallWidth: Int = 320
 | 
			
		||||
@@ -69,7 +72,10 @@ export type ProductTypes =
 | 
			
		||||
  | 'newestProducts'
 | 
			
		||||
 | 
			
		||||
export type ProductVariables = { field?: ProductTypes } & Images &
 | 
			
		||||
  Omit<GetAllProductsQueryVariables, ProductTypes | keyof ProductImageVariables>
 | 
			
		||||
  Omit<
 | 
			
		||||
    GetAllProductsQueryVariables,
 | 
			
		||||
    ProductTypes | keyof ProductImageVariables | 'hasLocale'
 | 
			
		||||
  >
 | 
			
		||||
 | 
			
		||||
async function getAllProducts(opts?: {
 | 
			
		||||
  variables?: ProductVariables
 | 
			
		||||
@@ -96,9 +102,12 @@ async function getAllProducts({
 | 
			
		||||
} = {}): Promise<GetAllProductsResult> {
 | 
			
		||||
  config = getConfig(config)
 | 
			
		||||
 | 
			
		||||
  const locale = vars.locale || config.locale
 | 
			
		||||
  const variables: GetAllProductsQueryVariables = {
 | 
			
		||||
    ...config.imageVariables,
 | 
			
		||||
    ...vars,
 | 
			
		||||
    locale,
 | 
			
		||||
    hasLocale: !!locale,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!FIELDS.includes(field)) {
 | 
			
		||||
@@ -115,11 +124,16 @@ async function getAllProducts({
 | 
			
		||||
    query,
 | 
			
		||||
    { variables }
 | 
			
		||||
  )
 | 
			
		||||
  const products = data.site?.[field]?.edges
 | 
			
		||||
  const edges = data.site?.[field]?.edges
 | 
			
		||||
  const products = filterEdges(edges as RecursiveRequired<typeof edges>)
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    products: filterEdges(products as RecursiveRequired<typeof products>),
 | 
			
		||||
  if (locale && config.applyLocale) {
 | 
			
		||||
    products.forEach((product: RecursivePartial<ProductEdge>) => {
 | 
			
		||||
      if (product.node) setProductLocaleMeta(product.node)
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return { products }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default getAllProducts
 | 
			
		||||
 
 | 
			
		||||
@@ -3,11 +3,14 @@ import type {
 | 
			
		||||
  GetProductQueryVariables,
 | 
			
		||||
} from 'lib/bigcommerce/schema'
 | 
			
		||||
import type { RecursivePartial, RecursiveRequired } from '../utils/types'
 | 
			
		||||
import setProductLocaleMeta from '../utils/set-product-locale-meta'
 | 
			
		||||
import { productInfoFragment } from '../fragments/product'
 | 
			
		||||
import { BigcommerceConfig, getConfig, Images } from '..'
 | 
			
		||||
 | 
			
		||||
export const getProductQuery = /* GraphQL */ `
 | 
			
		||||
  query getProduct(
 | 
			
		||||
    $hasLocale: Boolean = false
 | 
			
		||||
    $locale: String = "null"
 | 
			
		||||
    $path: String!
 | 
			
		||||
    $imgSmallWidth: Int = 320
 | 
			
		||||
    $imgSmallHeight: Int
 | 
			
		||||
@@ -42,8 +45,10 @@ export type GetProductResult<
 | 
			
		||||
  T extends { product?: any } = { product?: ProductNode }
 | 
			
		||||
> = T
 | 
			
		||||
 | 
			
		||||
export type ProductVariables = Images &
 | 
			
		||||
  ({ path: string; slug?: never } | { path?: never; slug: string })
 | 
			
		||||
export type ProductVariables = Images & { locale?: string } & (
 | 
			
		||||
    | { path: string; slug?: never }
 | 
			
		||||
    | { path?: never; slug: string }
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
async function getProduct(opts: {
 | 
			
		||||
  variables: ProductVariables
 | 
			
		||||
@@ -66,9 +71,13 @@ async function getProduct({
 | 
			
		||||
  config?: BigcommerceConfig
 | 
			
		||||
}): Promise<GetProductResult> {
 | 
			
		||||
  config = getConfig(config)
 | 
			
		||||
 | 
			
		||||
  const locale = vars.locale || config.locale
 | 
			
		||||
  const variables: GetProductQueryVariables = {
 | 
			
		||||
    ...config.imageVariables,
 | 
			
		||||
    ...vars,
 | 
			
		||||
    locale,
 | 
			
		||||
    hasLocale: !!locale,
 | 
			
		||||
    path: slug ? `/${slug}/` : vars.path!,
 | 
			
		||||
  }
 | 
			
		||||
  const { data } = await config.fetch<RecursivePartial<GetProductQuery>>(
 | 
			
		||||
@@ -78,6 +87,10 @@ async function getProduct({
 | 
			
		||||
  const product = data.site?.route?.node
 | 
			
		||||
 | 
			
		||||
  if (product?.__typename === 'Product') {
 | 
			
		||||
    if (locale && config.applyLocale) {
 | 
			
		||||
      setProductLocaleMeta(product)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      product: product as RecursiveRequired<typeof product>,
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								lib/bigcommerce/api/utils/set-product-locale-meta.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								lib/bigcommerce/api/utils/set-product-locale-meta.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
import type { ProductNode } from '../operations/get-all-products'
 | 
			
		||||
import type { RecursivePartial } from './types'
 | 
			
		||||
 | 
			
		||||
export default function setProductLocaleMeta(
 | 
			
		||||
  node: RecursivePartial<ProductNode>
 | 
			
		||||
) {
 | 
			
		||||
  if (node.localeMeta?.edges) {
 | 
			
		||||
    node.localeMeta.edges = node.localeMeta.edges.filter((edge) => {
 | 
			
		||||
      const { key, value } = edge?.node ?? {}
 | 
			
		||||
      if (key && key in node) {
 | 
			
		||||
        ;(node as any)[key] = value
 | 
			
		||||
        return false
 | 
			
		||||
      }
 | 
			
		||||
      return true
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    if (!node.localeMeta.edges.length) {
 | 
			
		||||
      delete node.localeMeta
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								lib/bigcommerce/schema.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								lib/bigcommerce/schema.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1807,6 +1807,20 @@ export type ProductInfoFragment = { __typename?: 'Product' } & Pick<
 | 
			
		||||
        >
 | 
			
		||||
      >
 | 
			
		||||
    }
 | 
			
		||||
    localeMeta: { __typename?: 'MetafieldConnection' } & {
 | 
			
		||||
      edges?: Maybe<
 | 
			
		||||
        Array<
 | 
			
		||||
          Maybe<
 | 
			
		||||
            { __typename?: 'MetafieldEdge' } & {
 | 
			
		||||
              node: { __typename?: 'Metafields' } & Pick<
 | 
			
		||||
                Metafields,
 | 
			
		||||
                'key' | 'value'
 | 
			
		||||
              >
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
        >
 | 
			
		||||
      >
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
export type ProductConnnectionFragment = {
 | 
			
		||||
@@ -1848,6 +1862,8 @@ export type GetAllProductPathsQuery = { __typename?: 'Query' } & {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type GetAllProductsQueryVariables = Exact<{
 | 
			
		||||
  hasLocale?: Maybe<Scalars['Boolean']>
 | 
			
		||||
  locale?: Maybe<Scalars['String']>
 | 
			
		||||
  entityIds?: Maybe<Array<Scalars['Int']>>
 | 
			
		||||
  first?: Maybe<Scalars['Int']>
 | 
			
		||||
  imgSmallWidth?: Maybe<Scalars['Int']>
 | 
			
		||||
@@ -1880,6 +1896,8 @@ export type GetAllProductsQuery = { __typename?: 'Query' } & {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type GetProductQueryVariables = Exact<{
 | 
			
		||||
  hasLocale?: Maybe<Scalars['Boolean']>
 | 
			
		||||
  locale?: Maybe<Scalars['String']>
 | 
			
		||||
  path: Scalars['String']
 | 
			
		||||
  imgSmallWidth?: Maybe<Scalars['Int']>
 | 
			
		||||
  imgSmallHeight?: Maybe<Scalars['Int']>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { useMemo } from 'react'
 | 
			
		||||
import { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
 | 
			
		||||
import { getConfig } from '@lib/bigcommerce/api'
 | 
			
		||||
import getAllProducts from '@lib/bigcommerce/api/operations/get-all-products'
 | 
			
		||||
import getSiteInfo from '@lib/bigcommerce/api/operations/get-site-info'
 | 
			
		||||
import getAllPages from '@lib/bigcommerce/api/operations/get-all-pages'
 | 
			
		||||
@@ -12,19 +13,22 @@ export async function getStaticProps({
 | 
			
		||||
  preview,
 | 
			
		||||
  locale,
 | 
			
		||||
}: GetStaticPropsContext) {
 | 
			
		||||
  console.log('LOCALE', locale)
 | 
			
		||||
  const config = getConfig({ locale })
 | 
			
		||||
 | 
			
		||||
  const { products: featuredProducts } = await getAllProducts({
 | 
			
		||||
    variables: { field: 'featuredProducts', first: 6 },
 | 
			
		||||
    config,
 | 
			
		||||
  })
 | 
			
		||||
  const { products: bestSellingProducts } = await getAllProducts({
 | 
			
		||||
    variables: { field: 'bestSellingProducts', first: 6 },
 | 
			
		||||
    config,
 | 
			
		||||
  })
 | 
			
		||||
  const { products: newestProducts } = await getAllProducts({
 | 
			
		||||
    variables: { field: 'newestProducts', first: 12 },
 | 
			
		||||
    config,
 | 
			
		||||
  })
 | 
			
		||||
  const { categories, brands } = await getSiteInfo()
 | 
			
		||||
  const { pages } = await getAllPages()
 | 
			
		||||
  const { categories, brands } = await getSiteInfo({ config })
 | 
			
		||||
  const { pages } = await getAllPages({ config })
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    props: {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,10 @@
 | 
			
		||||
import { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
 | 
			
		||||
import {
 | 
			
		||||
  GetStaticPathsContext,
 | 
			
		||||
  GetStaticPropsContext,
 | 
			
		||||
  InferGetStaticPropsType,
 | 
			
		||||
} from 'next'
 | 
			
		||||
import { useRouter } from 'next/router'
 | 
			
		||||
import { getConfig } from '@lib/bigcommerce/api'
 | 
			
		||||
import getAllPages from '@lib/bigcommerce/api/operations/get-all-pages'
 | 
			
		||||
import getProduct from '@lib/bigcommerce/api/operations/get-product'
 | 
			
		||||
import { Layout } from '@components/core'
 | 
			
		||||
@@ -8,9 +13,15 @@ import getAllProductPaths from '@lib/bigcommerce/api/operations/get-all-product-
 | 
			
		||||
 | 
			
		||||
export async function getStaticProps({
 | 
			
		||||
  params,
 | 
			
		||||
  locale,
 | 
			
		||||
}: GetStaticPropsContext<{ slug: string }>) {
 | 
			
		||||
  const { pages } = await getAllPages()
 | 
			
		||||
  const { product } = await getProduct({ variables: { slug: params!.slug } })
 | 
			
		||||
  const config = getConfig({ locale })
 | 
			
		||||
 | 
			
		||||
  const { pages } = await getAllPages({ config })
 | 
			
		||||
  const { product } = await getProduct({
 | 
			
		||||
    variables: { slug: params!.slug },
 | 
			
		||||
    config,
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  if (!product) {
 | 
			
		||||
    throw new Error(`Product with slug '${params!.slug}' not found`)
 | 
			
		||||
@@ -22,11 +33,19 @@ export async function getStaticProps({
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function getStaticPaths() {
 | 
			
		||||
export async function getStaticPaths({ locales }: GetStaticPathsContext) {
 | 
			
		||||
  const { products } = await getAllProductPaths()
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    paths: products.map((product) => `/product${product.node.path}`),
 | 
			
		||||
    paths: locales
 | 
			
		||||
      ? locales.reduce<string[]>((arr, locale) => {
 | 
			
		||||
          // Add a product path for every locale
 | 
			
		||||
          products.forEach((product) => {
 | 
			
		||||
            arr.push(`/${locale}/product${product.node.path}`)
 | 
			
		||||
          })
 | 
			
		||||
          return arr
 | 
			
		||||
        }, [])
 | 
			
		||||
      : products.map((product) => `/product${product.node.path}`),
 | 
			
		||||
    // If your store has tons of products, enable fallback mode to improve build times!
 | 
			
		||||
    fallback: false,
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user