Add configuration to show product options when there's one variant available

This commit is contained in:
tniezg
2021-07-29 13:02:57 +02:00
parent 2c4e2e4cb4
commit 744a8b998e
13 changed files with 167 additions and 74 deletions

View File

@@ -0,0 +1,72 @@
import * as qs from 'qs'
import { errors } from '@spree/storefront-api-v2-sdk'
import type { CreateFetcher } from '@spree/storefront-api-v2-sdk/types/interfaces/ClientConfig'
import { Request } from 'node-fetch'
// TODO: Fix rawFetch any type.
const createCreateFetchFetcher =
({ fetch: rawFetch }): CreateFetcher =>
(fetcherOptions) => {
const { FetchError } = errors
const sharedHeaders = {
'Content-Type': 'application/json',
}
return {
fetch: async (fetchOptions) => {
// This fetcher always returns request equal null,
// because @vercel/fetch doesn't accept a Request object as argument
// and it's not used by NJC anyway.
try {
const { url, params, method, headers } = fetchOptions
const absoluteUrl = new URL(url, fetcherOptions.host)
let payload
switch (method.toUpperCase()) {
case 'PUT':
case 'POST':
case 'DELETE':
case 'PATCH':
payload = { body: JSON.stringify(params) }
break
default:
payload = null
absoluteUrl.search = qs.stringify(params, {
arrayFormat: 'brackets',
})
}
try {
const response = await rawFetch(absoluteUrl.toString(), {
method,
headers: { ...sharedHeaders, ...headers },
...payload,
})
const data = await response.json()
if (!response.ok) {
// Use the "traditional" approach and reject non 2xx responses.
throw new FetchError(response, null, data)
}
return {
// Add response key to the prototype so it can be passed inside the GraphQLFetcherResult type.
// TODO: Search for a better solution than adding response to the prototype.
data: Object.setPrototypeOf({ data }, { response }),
}
} catch (error) {
if (error instanceof TypeError) {
throw new FetchError(null, null, null)
}
throw error
}
} catch (error) {
throw new FetchError(null, null, null, error.message)
}
},
}
}
export default createCreateFetchFetcher

View File

@@ -5,7 +5,7 @@ import type {
} from '@commerce/types/product'
import type {
JsonApiListResponse,
JsonApiResponse,
JsonApiSingleResponse,
} from '@spree/storefront-api-v2-sdk/types/interfaces/JsonApi'
import type { ProductAttr } from '@spree/storefront-api-v2-sdk/types/interfaces/Product'
import type { RelationType } from '@spree/storefront-api-v2-sdk/types/interfaces/Relationships'
@@ -16,7 +16,7 @@ import getMediaGallery from './getMediaGallery'
import { findIncludedOfType } from './jsonApi'
const normalizeProduct = (
spreeSuccessResponse: JsonApiResponse | JsonApiListResponse,
spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse,
spreeProduct: ProductAttr
) => {
const spreeImageRecords = findIncludedOfType(
@@ -27,7 +27,7 @@ const normalizeProduct = (
const images = getMediaGallery(
spreeImageRecords,
createGetAbsoluteImageUrl(requireConfigValue('spreeImageHost'))
createGetAbsoluteImageUrl(requireConfigValue('spreeImageHost') as string)
)
const price: ProductPrice = {
@@ -41,6 +41,10 @@ const normalizeProduct = (
const hasNonMasterVariants =
(spreeProduct.relationships.variants.data as RelationType[]).length > 1
const showOptions =
(requireConfigValue('showSingleVariantOptions') as boolean) ||
hasNonMasterVariants
let variants: ProductVariant[]
let options: ProductOption[] = []
@@ -53,7 +57,7 @@ const normalizeProduct = (
variants = spreeVariantRecords.map((spreeVariantRecord) => {
let variantOptions: ProductOption[] = []
if (hasNonMasterVariants) {
if (showOptions) {
const spreeOptionValues = findIncludedOfType(
spreeSuccessResponse,
spreeVariantRecord,