Allow placeholder images for products and line items without images

This commit is contained in:
tniezg 2021-08-25 11:34:22 +02:00
parent 448100290d
commit be0e246699
5 changed files with 49 additions and 2 deletions

View File

@ -14,3 +14,5 @@ NEXT_PUBLIC_SPREE_CATEGORIES_TAXONOMY_ID=1
NEXT_PUBLIC_SPREE_BRANDS_TAXONOMY_ID=27 NEXT_PUBLIC_SPREE_BRANDS_TAXONOMY_ID=27
NEXT_PUBLIC_SPREE_SHOW_SINGLE_VARIANT_OPTIONS=false NEXT_PUBLIC_SPREE_SHOW_SINGLE_VARIANT_OPTIONS=false
NEXT_PUBLIC_SPREE_LAST_UPDATED_PRODUCTS_PRERENDER_COUNT=10 NEXT_PUBLIC_SPREE_LAST_UPDATED_PRODUCTS_PRERENDER_COUNT=10
NEXT_PUBLIC_SPREE_PRODUCT_PLACEHOLDER_IMAGE_URL=/product-img-placeholder.svg
NEXT_PUBLIC_SPREE_LINE_ITEM_PLACEHOLDER_IMAGE_URL=/product-img-placeholder.svg

View File

@ -1,6 +1,7 @@
import forceIsomorphicConfigValues from './utils/force-isomorphic-config-values' import forceIsomorphicConfigValues from './utils/force-isomorphic-config-values'
import requireConfig from './utils/require-config' import requireConfig from './utils/require-config'
import validateCookieExpire from './utils/validate-cookie-expire' import validateCookieExpire from './utils/validate-cookie-expire'
import validatePlaceholderImageUrl from './utils/validate-placeholder-image-url'
import validateProductsPrerenderCount from './utils/validate-products-prerender-count' import validateProductsPrerenderCount from './utils/validate-products-prerender-count'
const isomorphicConfig = { const isomorphicConfig = {
@ -18,6 +19,12 @@ const isomorphicConfig = {
lastUpdatedProductsPrerenderCount: validateProductsPrerenderCount( lastUpdatedProductsPrerenderCount: validateProductsPrerenderCount(
process.env.NEXT_PUBLIC_SPREE_LAST_UPDATED_PRODUCTS_PRERENDER_COUNT process.env.NEXT_PUBLIC_SPREE_LAST_UPDATED_PRODUCTS_PRERENDER_COUNT
), ),
productPlaceholderImageUrl: validatePlaceholderImageUrl(
process.env.NEXT_PUBLIC_SPREE_PRODUCT_PLACEHOLDER_IMAGE_URL
),
lineItemPlaceholderImageUrl: validatePlaceholderImageUrl(
process.env.NEXT_PUBLIC_SPREE_LINE_ITEM_PLACEHOLDER_IMAGE_URL
),
} }
export default forceIsomorphicConfigValues( export default forceIsomorphicConfigValues(
@ -33,6 +40,8 @@ export default forceIsomorphicConfigValues(
'brandsTaxonomyId', 'brandsTaxonomyId',
'showSingleVariantOptions', 'showSingleVariantOptions',
'lastUpdatedProductsPrerenderCount', 'lastUpdatedProductsPrerenderCount',
'productPlaceholderImageUrl',
'lineItemPlaceholderImageUrl',
] ]
) )

View File

@ -21,6 +21,11 @@ import type {
OptionTypeAttr, OptionTypeAttr,
VariantAttr, VariantAttr,
} from '@framework/types' } from '@framework/types'
import type { Image } from '@commerce/types/common'
const placeholderImage = requireConfigValue('lineItemPlaceholderImageUrl') as
| string
| false
const isColorProductOption = (productOptionType: OptionTypeAttr) => { const isColorProductOption = (productOptionType: OptionTypeAttr) => {
return productOptionType.attributes.presentation === 'Color' return productOptionType.attributes.presentation === 'Color'
@ -74,6 +79,10 @@ const normalizeVariant = (
lineItemImage = productImage lineItemImage = productImage
} }
const image: Image =
lineItemImage ??
(placeholderImage === false ? undefined : { url: placeholderImage })
return { return {
id: spreeVariant.id, id: spreeVariant.id,
sku: spreeVariant.attributes.sku, sku: spreeVariant.attributes.sku,
@ -81,7 +90,7 @@ const normalizeVariant = (
requiresShipping: true, requiresShipping: true,
price: parseFloat(spreeVariant.attributes.price), price: parseFloat(spreeVariant.attributes.price),
listPrice: parseFloat(spreeVariant.attributes.price), listPrice: parseFloat(spreeVariant.attributes.price),
image: lineItemImage, image,
isInStock: spreeVariant.attributes.in_stock, isInStock: spreeVariant.attributes.in_stock,
availableForSale: spreeVariant.attributes.purchasable, availableForSale: spreeVariant.attributes.purchasable,
...(spreeVariant.attributes.weight === '0.0' ...(spreeVariant.attributes.weight === '0.0'

View File

@ -1,5 +1,6 @@
import type { import type {
Product, Product,
ProductImage,
ProductOption, ProductOption,
ProductPrice, ProductPrice,
ProductVariant, ProductVariant,
@ -18,6 +19,10 @@ import { findIncluded, findIncludedOfType } from './find-json-api-documents'
import getProductPath from './get-product-path' import getProductPath from './get-product-path'
import MissingPrimaryVariantError from '@framework/errors/MissingPrimaryVariantError' import MissingPrimaryVariantError from '@framework/errors/MissingPrimaryVariantError'
const placeholderImage = requireConfigValue('productPlaceholderImageUrl') as
| string
| false
const normalizeProduct = ( const normalizeProduct = (
spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse, spreeSuccessResponse: JsonApiSingleResponse | JsonApiListResponse,
spreeProduct: ProductAttr spreeProduct: ProductAttr
@ -44,11 +49,18 @@ const normalizeProduct = (
'images' 'images'
) )
const images = getMediaGallery( const productImages = getMediaGallery(
spreeImageRecords, spreeImageRecords,
createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string) createGetAbsoluteImageUrl(requireConfigValue('imageHost') as string)
) )
const images: ProductImage[] =
productImages.length === 0
? placeholderImage === false
? []
: [{ url: placeholderImage }]
: productImages
const price: ProductPrice = { const price: ProductPrice = {
value: parseFloat(spreeProduct.attributes.price), value: parseFloat(spreeProduct.attributes.price),
currencyCode: spreeProduct.attributes.currency, currencyCode: spreeProduct.attributes.currency,

View File

@ -0,0 +1,15 @@
const validatePlaceholderImageUrl = (
placeholderUrlOrFalse: unknown
): string | false => {
if (!placeholderUrlOrFalse || placeholderUrlOrFalse === 'false') {
return false
}
if (typeof placeholderUrlOrFalse === 'string') {
return placeholderUrlOrFalse
}
throw new TypeError('placeholderUrlOrFalse must be a string or falsy.')
}
export default validatePlaceholderImageUrl