commerce/packages/saleor/utils/normalize.ts
2022-01-14 18:29:24 -05:00

134 lines
3.8 KiB
TypeScript

import { Product } from '@commerce/types/product'
import { Product as SaleorProduct, Checkout, CheckoutLine, Money, ProductVariant } from '../schema'
import type { Cart, LineItem } from '../types'
// TODO: Check nextjs-commerce bug if no images are added for a product
const placeholderImg = '/product-img-placeholder.svg'
const money = ({ amount, currency }: Money) => {
return {
value: +amount,
currencyCode: currency || 'USD',
}
}
const normalizeProductOptions = (options: ProductVariant[]) => {
return options
?.map((option) => option?.attributes)
.flat(1)
.reduce<any>((acc, x) => {
if (acc.find(({ displayName }: any) => displayName === x.attribute.name)) {
return acc.map((opt: any) => {
return opt.displayName === x.attribute.name
? {
...opt,
values: [
...opt.values,
...x.values.map((value: any) => ({
label: value?.name,
})),
],
}
: opt
})
}
return acc.concat({
__typename: 'MultipleChoiceOption',
displayName: x.attribute.name,
variant: 'size',
values: x.values.map((value: any) => ({
label: value?.name,
})),
})
}, [])
}
const normalizeProductVariants = (variants: ProductVariant[]) => {
return variants?.map((variant) => {
const { id, sku, name, pricing } = variant
const price = pricing?.price?.net && money(pricing.price.net)?.value
return {
id,
name,
sku: sku ?? id,
price,
listPrice: price,
requiresShipping: true,
options: normalizeProductOptions([variant]),
}
})
}
export function normalizeProduct(productNode: SaleorProduct): Product {
const { id, name, media = [], variants, description, slug, pricing, ...rest } = productNode
const product = {
id,
name,
vendor: '',
description: description ? JSON.parse(description)?.blocks[0]?.data.text : '',
path: `/${slug}`,
slug: slug?.replace(/^\/+|\/+$/g, ''),
price: (pricing?.priceRange?.start?.net && money(pricing.priceRange.start.net)) || {
value: 0,
currencyCode: 'USD',
},
// TODO: Check nextjs-commerce bug if no images are added for a product
images: media?.length ? media : [{ url: placeholderImg }],
variants: variants && variants.length > 0 ? normalizeProductVariants(variants as ProductVariant[]) : [],
options: variants && variants.length > 0 ? normalizeProductOptions(variants as ProductVariant[]) : [],
...rest,
}
return product as Product
}
export function normalizeCart(checkout: Checkout): Cart {
const lines = checkout.lines as CheckoutLine[]
const lineItems: LineItem[] = lines.length > 0 ? lines?.map<LineItem>(normalizeLineItem) : []
return {
id: checkout.id,
customerId: '',
email: '',
createdAt: checkout.created,
currency: {
code: checkout.totalPrice?.currency!,
},
taxesIncluded: false,
lineItems,
lineItemsSubtotalPrice: checkout.subtotalPrice?.gross?.amount!,
subtotalPrice: checkout.subtotalPrice?.gross?.amount!,
totalPrice: checkout.totalPrice?.gross.amount!,
discounts: [],
}
}
function normalizeLineItem({ id, variant, quantity }: CheckoutLine): LineItem {
return {
id,
variantId: String(variant?.id),
productId: String(variant?.id),
name: `${variant.product.name}`,
quantity,
variant: {
id: String(variant?.id),
sku: variant?.sku ?? '',
name: variant?.name!,
image: {
url: variant?.media![0] ? variant?.media![0].url : placeholderImg,
},
requiresShipping: false,
price: variant?.pricing?.price?.gross.amount!,
listPrice: 0,
},
path: String(variant?.product?.slug),
discounts: [],
options: [],
}
}