diff --git a/.changeset/eager-nails-bake.md b/.changeset/eager-nails-bake.md new file mode 100644 index 0000000000..cce2f53695 --- /dev/null +++ b/.changeset/eager-nails-bake.md @@ -0,0 +1,10 @@ +--- +"@bigcommerce/catalyst-core": minor +--- + +Fetch product inventory data with a separate GQL query with no caching + +## Migration +The files to be rebased for this change to be applied are: +- core/app/[locale]/(default)/product/[slug]/page-data.ts +- core/app/[locale]/(default)/product/[slug]/page.tsx \ No newline at end of file diff --git a/core/app/[locale]/(default)/product/[slug]/page-data.ts b/core/app/[locale]/(default)/product/[slug]/page-data.ts index 1959e8589f..a3820662ab 100644 --- a/core/app/[locale]/(default)/product/[slug]/page-data.ts +++ b/core/app/[locale]/(default)/product/[slug]/page-data.ts @@ -255,7 +255,7 @@ export const getStreamableProductVariant = cache( document: StreamableProductVariantBySkuQuery, variables, customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product?.variants; @@ -306,6 +306,36 @@ const StreamableProductQuery = graphql( minPurchaseQuantity maxPurchaseQuantity warranty + ...ProductViewedFragment + ...ProductSchemaFragment + } + } + } + `, + [ProductViewedFragment, ProductSchemaFragment], +); + +type Variables = VariablesOf; + +export const getStreamableProduct = cache( + async (variables: Variables, customerAccessToken?: string) => { + const { data } = await client.fetch({ + document: StreamableProductQuery, + variables, + customerAccessToken, + fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + }); + + return data.site.product; + }, +); + +const StreamableProductInventoryQuery = graphql( + ` + query StreamableProductInventoryQuery($entityId: Int!) { + site { + product(entityId: $entityId) { + sku inventory { hasVariantInventory isInStock @@ -320,25 +350,23 @@ const StreamableProductQuery = graphql( availabilityV2 { status } - ...ProductViewedFragment ...ProductVariantsInventoryFragment - ...ProductSchemaFragment } } } `, - [ProductViewedFragment, ProductSchemaFragment, ProductVariantsInventoryFragment], + [ProductVariantsInventoryFragment], ); -type Variables = VariablesOf; +type ProductInventoryVariables = VariablesOf; -export const getStreamableProduct = cache( - async (variables: Variables, customerAccessToken?: string) => { +export const getStreamableProductInventory = cache( + async (variables: ProductInventoryVariables, customerAccessToken?: string) => { const { data } = await client.fetch({ - document: StreamableProductQuery, + document: StreamableProductInventoryQuery, variables, customerAccessToken, - fetchOptions: customerAccessToken ? { cache: 'no-store' } : { next: { revalidate } }, + fetchOptions: { cache: 'no-store' }, }); return data.site.product; diff --git a/core/app/[locale]/(default)/product/[slug]/page.tsx b/core/app/[locale]/(default)/product/[slug]/page.tsx index bdde5b1230..e4aa0dba94 100644 --- a/core/app/[locale]/(default)/product/[slug]/page.tsx +++ b/core/app/[locale]/(default)/product/[slug]/page.tsx @@ -27,6 +27,7 @@ import { getProductPricingAndRelatedProducts, getStreamableInventorySettingsQuery, getStreamableProduct, + getStreamableProductInventory, getStreamableProductVariant, } from './page-data'; @@ -117,8 +118,22 @@ export default async function Product({ params, searchParams }: Props) { const streamableProductSku = Streamable.from(async () => (await streamableProduct).sku); + const streamableProductInventory = Streamable.from(async () => { + const variables = { + entityId: Number(productId), + }; + + const product = await getStreamableProductInventory(variables, customerAccessToken); + + if (!product) { + return notFound(); + } + + return product; + }); + const streamableProductVariant = Streamable.from(async () => { - const product = await streamableProduct; + const product = await streamableProductInventory; if (!product.inventory.hasVariantInventory) { return undefined; @@ -188,7 +203,7 @@ export default async function Product({ params, searchParams }: Props) { }); const streameableCtaLabel = Streamable.from(async () => { - const product = await streamableProduct; + const product = await streamableProductInventory; if (product.availabilityV2.status === 'Unavailable') { return t('ProductDetails.Submit.unavailable'); @@ -206,7 +221,7 @@ export default async function Product({ params, searchParams }: Props) { }); const streameableCtaDisabled = Streamable.from(async () => { - const product = await streamableProduct; + const product = await streamableProductInventory; if (product.availabilityV2.status === 'Unavailable') { return true; @@ -253,7 +268,7 @@ export default async function Product({ params, searchParams }: Props) { const streamableStockDisplayData = Streamable.from(async () => { const [product, variant, inventorySetting] = await Streamable.all([ - streamableProduct, + streamableProductInventory, streamableProductVariant, streamableInventorySettings, ]); @@ -343,7 +358,7 @@ export default async function Product({ params, searchParams }: Props) { const streamableBackorderDisplayData = Streamable.from(async () => { const [product, variant, inventorySetting] = await Streamable.all([ - streamableProduct, + streamableProductInventory, streamableProductVariant, streamableInventorySettings, ]);