@nacelle/compatibility-connector
Version:
Connect @nacelle/client-js-sdk to Nacelle's v2 back end with minimal code changes
115 lines (108 loc) • 4.39 kB
text/typescript
import { transformMedia } from './transformMedia';
import { transformSourceEntryId } from './transformSourceEntryId';
import type { NacelleProduct, ProductVariant, Media } from '@nacelle/types';
import type { Product } from 'storefrontSdkV1';
export function transformProducts(
products: Product[],
locale: string
): NacelleProduct[] {
return products.map((product: Product) => {
const formatPrice = (price: number): string => {
if (Number.isInteger(price)) return price.toFixed(1);
return price.toString();
};
const hasVariant =
Array.isArray(product.variants) && product.variants.length;
const variantPrices =
hasVariant &&
product.variants
?.map((variant) => parseFloat(variant.price))
// We provide a sort function here because by default,
// "all non-undefined array elements are sorted by
// converting them to strings and comparing strings
// in UTF-16 code units order." For more details, see:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#description
.sort((a, b) => a - b)
.map((price) => formatPrice(price));
const priceCurrency = hasVariant
? product.variants[0]?.priceCurrency
: null;
return {
availableForSale: product.availableForSale as boolean,
createdAt: product.createdAt as number,
description: product.content?.description || null,
featuredMedia: transformMedia(product.content?.featuredMedia),
globalHandle: product.content?.handle
? `${product.content?.handle}::${locale}`
: '',
handle: product.content?.handle || '',
id: product.nacelleEntryId,
indexedAt: product.indexedAt as number,
locale,
media:
product.content?.media?.map(
(media) => transformMedia(media) as Media
) || null,
metafields: product.metafields,
pimSyncSource: '',
pimSyncSourceDomain: '',
pimSyncSourceProductId: transformSourceEntryId(product.sourceEntryId),
priceRange: Array.isArray(variantPrices)
? {
min: variantPrices[0],
max: variantPrices[variantPrices.length - 1],
currencyCode: priceCurrency
}
: null,
productType: product.productType,
tags: product.tags,
title: product.content?.title || null,
updatedAt: product.updatedAt,
vendor: product.vendor,
variants: product.variants?.map((variant): ProductVariant => {
const transformedVariant: ProductVariant = {
availableForSale: variant.availableForSale,
compareAtPrice:
variant.compareAtPrice &&
formatPrice(Number(variant.compareAtPrice)),
compareAtPriceCurrency:
variant.compareAtPrice &&
formatPrice(Number(variant.compareAtPrice)),
featuredMedia: transformMedia(variant.content?.featuredMedia),
id: transformSourceEntryId(variant.sourceEntryId),
metafields: variant.metafields,
price: formatPrice(Number(variant.price)),
priceCurrency: variant.priceCurrency,
priceRules:
Array.isArray(variant.priceRules) && variant.priceRules.length
? variant.priceRules?.map((priceRule) => ({
...priceRule,
comparedAtPrice: priceRule.comparedAtPrice
? formatPrice(Number(priceRule.comparedAtPrice))
: null,
price: formatPrice(Number(priceRule.price)),
priceBreaks:
priceRule.priceBreaks &&
priceRule.priceBreaks.map((priceBreak) => ({
...priceBreak,
price: formatPrice(Number(priceBreak.price))
}))
}))
: [],
quantityAvailable: variant.quantityAvailable,
selectedOptions:
variant.content?.selectedOptions?.map(({ name, value }) => ({
name,
value
})) || null,
sku: variant.sku,
swatchSrc: variant.content?.swatchSrc || null,
title: variant.content?.title || null,
weight: variant.weight,
weightUnit: variant.weightUnit
};
return transformedVariant;
})
};
});
}