mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 16:07:01 +00:00
Merge branch 'outgrow-reaction-commerce-provider' of github.com:outgrow/commerce into outgrow-reaction-commerce-provider
This commit is contained in:
commit
94c04bf564
@ -127,4 +127,3 @@ a {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
.fit {
|
.fit {
|
||||||
min-height: calc(100vh - 88px);
|
min-height: calc(100vh - 88px);
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,10 @@ const ProductView: FC<Props> = ({ product }) => {
|
|||||||
|
|
||||||
await addItem({
|
await addItem({
|
||||||
productId: String(product.id),
|
productId: String(product.id),
|
||||||
variantId: String(selectedVariant.sku),
|
variantId: String(selectedVariant.id),
|
||||||
pricing: {
|
pricing: {
|
||||||
amount: selectedVariant.price,
|
amount: selectedVariant.price,
|
||||||
currencyCode: product.price.currencyCode,
|
currencyCode: product.price.currencyCode ?? 'USD',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
openSidebar()
|
openSidebar()
|
||||||
|
@ -63,6 +63,7 @@ export type ProductVariant = {
|
|||||||
// The variant's depth. If a depth was not explicitly specified on the
|
// The variant's depth. If a depth was not explicitly specified on the
|
||||||
// variant, this will be the product's depth.
|
// variant, this will be the product's depth.
|
||||||
depth?: Measurement
|
depth?: Measurement
|
||||||
|
options: ProductOption[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shopping cart, a.k.a Checkout
|
// Shopping cart, a.k.a Checkout
|
||||||
@ -109,6 +110,10 @@ export type CartItemBody = {
|
|||||||
variantId: string
|
variantId: string
|
||||||
productId?: string
|
productId?: string
|
||||||
quantity?: number
|
quantity?: number
|
||||||
|
pricing?: {
|
||||||
|
amount: number
|
||||||
|
currencyCode: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body used by the `getCart` operation handler
|
// Body used by the `getCart` operation handler
|
||||||
@ -167,18 +172,18 @@ export interface Product extends Entity {
|
|||||||
slug?: string
|
slug?: string
|
||||||
path?: string
|
path?: string
|
||||||
images: ProductImage[]
|
images: ProductImage[]
|
||||||
variants: ProductVariant2[]
|
variants: ProductVariant[]
|
||||||
price: ProductPrice
|
price: ProductPrice
|
||||||
options: ProductOption[]
|
options: ProductOption[]
|
||||||
sku?: string
|
sku?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProductOption extends Entity {
|
export interface ProductOption extends Entity {
|
||||||
displayName: string
|
displayName: string
|
||||||
values: ProductOptionValues[]
|
values: ProductOptionValues[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProductOptionValues {
|
export interface ProductOptionValues {
|
||||||
label: string
|
label: string
|
||||||
hexColors?: string[]
|
hexColors?: string[]
|
||||||
}
|
}
|
||||||
@ -188,11 +193,6 @@ interface ProductImage {
|
|||||||
alt?: string
|
alt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProductVariant2 {
|
|
||||||
id: string | number
|
|
||||||
options: ProductOption[]
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ProductPrice {
|
interface ProductPrice {
|
||||||
value: number
|
value: number
|
||||||
currencyCode: 'USD' | 'ARS' | string | undefined
|
currencyCode: 'USD' | 'ARS' | string | undefined
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { Cart } from '../../../types'
|
|
||||||
import type { CartHandlers } from '../'
|
import type { CartHandlers } from '../'
|
||||||
import getAnomymousCartQuery from '@framework/utils/queries/get-anonymous-cart'
|
import getAnonymousCartQuery from '@framework/utils/queries/get-anonymous-cart'
|
||||||
import accountCartByAccountIdQuery from '@framework/utils/queries/account-cart-by-account-id'
|
import accountCartByAccountIdQuery from '@framework/utils/queries/account-cart-by-account-id'
|
||||||
import getCartCookie from '@framework/api/utils/get-cart-cookie'
|
import getCartCookie from '@framework/api/utils/get-cart-cookie'
|
||||||
import reconcileCarts from '@framework/api/utils/reconcile-carts'
|
import reconcileCarts from '@framework/api/utils/reconcile-carts'
|
||||||
@ -9,7 +8,7 @@ import {
|
|||||||
REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
REACTION_CART_ID_COOKIE,
|
REACTION_CART_ID_COOKIE,
|
||||||
REACTION_CUSTOMER_TOKEN_COOKIE,
|
REACTION_CUSTOMER_TOKEN_COOKIE,
|
||||||
} from '@framework/const.ts'
|
} from '@framework/const'
|
||||||
import { normalizeCart } from '@framework/utils'
|
import { normalizeCart } from '@framework/utils'
|
||||||
|
|
||||||
// Return current cart info
|
// Return current cart info
|
||||||
@ -42,7 +41,7 @@ const getCart: CartHandlers['getCart'] = async ({ req, res, config }) => {
|
|||||||
} else if (cartId && anonymousCartToken) {
|
} else if (cartId && anonymousCartToken) {
|
||||||
const {
|
const {
|
||||||
data: { cart: rawAnonymousCart },
|
data: { cart: rawAnonymousCart },
|
||||||
} = await config.fetch(getAnomymousCartQuery, {
|
} = await config.fetch(getAnonymousCartQuery, {
|
||||||
variables: {
|
variables: {
|
||||||
cartId,
|
cartId,
|
||||||
cartToken: anonymousCartToken,
|
cartToken: anonymousCartToken,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import type { MutationHook } from '@commerce/utils/types'
|
import type { MutationHook } from '@commerce/utils/types'
|
||||||
import { CommerceError, ValidationError } from '@commerce/utils/errors'
|
import { CommerceError } from '@commerce/utils/errors'
|
||||||
import useCustomer from '../customer/use-customer'
|
import useCustomer from '../customer/use-customer'
|
||||||
import authenticateMutation from '../utils/mutations/authenticate'
|
import authenticateMutation from '../utils/mutations/authenticate'
|
||||||
import {
|
import {
|
||||||
|
@ -6,7 +6,10 @@
|
|||||||
},
|
},
|
||||||
"generates": {
|
"generates": {
|
||||||
"./framework/reactioncommerce/schema.d.ts": {
|
"./framework/reactioncommerce/schema.d.ts": {
|
||||||
"plugins": ["typescript", "typescript-operations"]
|
"plugins": ["typescript", "typescript-operations"],
|
||||||
|
"config": {
|
||||||
|
"avoidOptionals": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"./framework/reactioncommerce/schema.graphql": {
|
"./framework/reactioncommerce/schema.graphql": {
|
||||||
"plugins": ["schema-ast"]
|
"plugins": ["schema-ast"]
|
||||||
|
@ -1,119 +1,168 @@
|
|||||||
import { Product, Customer } from '@commerce/types'
|
import {
|
||||||
|
Product,
|
||||||
|
Customer,
|
||||||
|
ProductVariant,
|
||||||
|
ProductOption,
|
||||||
|
ProductOptionValues,
|
||||||
|
} from '@commerce/types'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
Cart as ReactionCart,
|
Cart as ReactionCart,
|
||||||
ProductPricingInfo,
|
|
||||||
CatalogProductVariant,
|
CatalogProductVariant,
|
||||||
CartItemEdge,
|
CartItemEdge,
|
||||||
CatalogItemProduct,
|
CatalogItemProduct,
|
||||||
CatalogProduct,
|
CatalogProduct,
|
||||||
ImageInfo,
|
ImageInfo,
|
||||||
Maybe,
|
CartItem,
|
||||||
} from '../schema'
|
} from '../schema'
|
||||||
|
|
||||||
import type { Cart, LineItem } from '../types'
|
import type { Cart, LineItem } from '../types'
|
||||||
|
|
||||||
type ProductOption = {
|
const normalizeProductImages = (images: ImageInfo[], name: string) =>
|
||||||
__typename?: string
|
|
||||||
id: string
|
|
||||||
displayName: string
|
|
||||||
values: any[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const money = ({ displayPrice }: ProductPricingInfo) => {
|
|
||||||
return {
|
|
||||||
displayPrice,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normalizeProductImages = (images: Maybe<ImageInfo>[], name: string) =>
|
|
||||||
images.map((image) => ({
|
images.map((image) => ({
|
||||||
url: image?.URLs?.original || image?.URLs?.medium || '',
|
url: image?.URLs?.original || image?.URLs?.medium || '',
|
||||||
alt: name,
|
alt: name,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const normalizeProductOption = ({ id, displayName, values }: ProductOption) => {
|
const normalizeProductOption = (variant: CatalogProductVariant) => {
|
||||||
return {
|
const option = <ProductOption>{
|
||||||
__typename: 'MultipleChoiceOption',
|
__typename: 'MultipleChoiceOption',
|
||||||
id,
|
id: variant._id,
|
||||||
displayName,
|
displayName: variant.attributeLabel,
|
||||||
values: values.map((value) => {
|
values: variant.optionTitle ? [{ label: variant.optionTitle }] : [],
|
||||||
let output: any = {
|
|
||||||
label: value,
|
|
||||||
}
|
|
||||||
if (displayName.toLowerCase() === 'color') {
|
|
||||||
output = {
|
|
||||||
...output,
|
|
||||||
hexColors: [value],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
option.values = option.values.map((value) =>
|
||||||
|
colorizeProductOptionValue(value, option.displayName)
|
||||||
|
)
|
||||||
|
|
||||||
|
return option
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeProductVariants = (variants: CatalogProductVariant[]) => {
|
function colorizeProductOptionValue(
|
||||||
return variants.map((variant) => {
|
value: ProductOptionValues,
|
||||||
const { _id, options, sku, title, pricing = [], variantId } = variant ?? {}
|
displayName: string
|
||||||
const variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice ?? 0
|
): ProductOptionValues {
|
||||||
|
if (displayName.toLowerCase() === 'color') {
|
||||||
return {
|
value.hexColors = [value.label]
|
||||||
id: _id ?? '',
|
}
|
||||||
name: title,
|
return value
|
||||||
sku: sku ?? variantId,
|
|
||||||
price: variantPrice,
|
|
||||||
listPrice: pricing[0]?.compareAtPrice?.amount ?? variantPrice,
|
|
||||||
requiresShipping: true,
|
|
||||||
options: options?.length
|
|
||||||
? options.map((option) => {
|
|
||||||
return normalizeProductOption({
|
|
||||||
id: option?._id ?? '',
|
|
||||||
displayName: option?.attributeLabel ?? '',
|
|
||||||
values: [option?.optionTitle],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
: [],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupProductOptionsByAttributeLabel(
|
const normalizeProductVariants = (
|
||||||
options: CatalogProductVariant[]
|
variants: Array<CatalogProductVariant>
|
||||||
) {
|
): ProductVariant[] => {
|
||||||
return options.reduce((groupedOptions, currentOption) => {
|
return variants.reduce(
|
||||||
const attributeLabelIndex = groupedOptions.findIndex((option) => {
|
(productVariants: ProductVariant[], variant: CatalogProductVariant) => {
|
||||||
return (
|
if (variantHasOptions(variant)) {
|
||||||
option.displayName.toLowerCase() ===
|
productVariants.push(...flatVariantOptions(variant))
|
||||||
currentOption?.attributeLabel.toLowerCase()
|
return productVariants
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sku, title, pricing = [], variantId } = variant ?? {}
|
||||||
|
const variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice ?? 0
|
||||||
|
|
||||||
|
productVariants.push(<ProductVariant>{
|
||||||
|
id: variantId ?? '',
|
||||||
|
name: title,
|
||||||
|
sku: sku ?? variantId,
|
||||||
|
price: variantPrice,
|
||||||
|
listPrice: pricing[0]?.compareAtPrice?.amount ?? variantPrice,
|
||||||
|
requiresShipping: true,
|
||||||
|
options: [normalizeProductOption(variant)],
|
||||||
|
})
|
||||||
|
|
||||||
|
return productVariants
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupProductOptionsByAttributeLabel(
|
||||||
|
variants: CatalogProductVariant[]
|
||||||
|
): ProductOption[] {
|
||||||
|
return variants.reduce(
|
||||||
|
(
|
||||||
|
groupedOptions: ProductOption[],
|
||||||
|
currentVariant: CatalogProductVariant
|
||||||
|
) => {
|
||||||
|
groupedOptions = mergeVariantOptionsWithExistingOptions(
|
||||||
|
groupedOptions,
|
||||||
|
currentVariant
|
||||||
)
|
)
|
||||||
})
|
|
||||||
|
|
||||||
if (attributeLabelIndex !== -1) {
|
if (variantHasOptions(currentVariant)) {
|
||||||
groupedOptions[attributeLabelIndex].values = [
|
(<CatalogProductVariant[]>currentVariant.options).forEach(
|
||||||
...groupedOptions[attributeLabelIndex].values,
|
(variantOption) => {
|
||||||
{
|
groupedOptions = mergeVariantOptionsWithExistingOptions(
|
||||||
label: currentOption?.optionTitle ?? '',
|
groupedOptions,
|
||||||
hexColors: [currentOption?.optionTitle] ?? '',
|
variantOption
|
||||||
},
|
)
|
||||||
]
|
}
|
||||||
} else {
|
)
|
||||||
groupedOptions = [
|
}
|
||||||
...groupedOptions,
|
|
||||||
normalizeProductOption({
|
|
||||||
id: currentOption?._id ?? '',
|
|
||||||
displayName: currentOption?.attributeLabel ?? '',
|
|
||||||
values: [currentOption?.optionTitle ?? ''],
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupedOptions
|
return groupedOptions
|
||||||
}, [] as ProductOption[])
|
},
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeVariantOptionsWithExistingOptions(
|
||||||
|
groupedOptions: ProductOption[],
|
||||||
|
currentVariant: CatalogProductVariant
|
||||||
|
): ProductOption[] {
|
||||||
|
const matchingOptionIndex = findCurrentVariantOptionsInGroupedOptions(
|
||||||
|
groupedOptions,
|
||||||
|
currentVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
return matchingOptionIndex !== -1
|
||||||
|
? mergeWithExistingOptions(
|
||||||
|
groupedOptions,
|
||||||
|
currentVariant,
|
||||||
|
matchingOptionIndex
|
||||||
|
)
|
||||||
|
: addNewProductOption(groupedOptions, currentVariant)
|
||||||
|
}
|
||||||
|
|
||||||
|
function findCurrentVariantOptionsInGroupedOptions(
|
||||||
|
groupedOptions: ProductOption[],
|
||||||
|
currentVariant: CatalogProductVariant
|
||||||
|
): number {
|
||||||
|
return groupedOptions.findIndex(
|
||||||
|
(option) =>
|
||||||
|
option.displayName.toLowerCase() ===
|
||||||
|
currentVariant.attributeLabel.toLowerCase()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeWithExistingOptions(
|
||||||
|
groupedOptions: ProductOption[],
|
||||||
|
currentVariant: CatalogProductVariant,
|
||||||
|
matchingOptionIndex: number
|
||||||
|
) {
|
||||||
|
const currentVariantOption = normalizeProductOption(currentVariant)
|
||||||
|
groupedOptions[matchingOptionIndex].values = [
|
||||||
|
...groupedOptions[matchingOptionIndex].values,
|
||||||
|
...currentVariantOption.values,
|
||||||
|
]
|
||||||
|
|
||||||
|
return groupedOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNewProductOption(
|
||||||
|
groupedOptions: ProductOption[],
|
||||||
|
currentVariant: CatalogProductVariant
|
||||||
|
) {
|
||||||
|
return [...groupedOptions, normalizeProductOption(currentVariant)]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeProduct(productNode: CatalogItemProduct): Product {
|
export function normalizeProduct(productNode: CatalogItemProduct): Product {
|
||||||
const product = productNode.product as CatalogProduct
|
const product = productNode.product
|
||||||
|
if (!product) {
|
||||||
|
return <Product>{}
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
_id,
|
_id,
|
||||||
@ -124,10 +173,8 @@ export function normalizeProduct(productNode: CatalogItemProduct): Product {
|
|||||||
sku,
|
sku,
|
||||||
media,
|
media,
|
||||||
pricing,
|
pricing,
|
||||||
vendor,
|
|
||||||
variants,
|
variants,
|
||||||
...rest
|
} = <CatalogProduct>product
|
||||||
} = product
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: productId ?? _id,
|
id: productId ?? _id,
|
||||||
@ -136,17 +183,20 @@ export function normalizeProduct(productNode: CatalogItemProduct): Product {
|
|||||||
slug: slug?.replace(/^\/+|\/+$/g, '') ?? '',
|
slug: slug?.replace(/^\/+|\/+$/g, '') ?? '',
|
||||||
path: slug ?? '',
|
path: slug ?? '',
|
||||||
sku: sku ?? '',
|
sku: sku ?? '',
|
||||||
images: media?.length ? normalizeProductImages(media, title ?? '') : [],
|
images: media?.length
|
||||||
|
? normalizeProductImages(<ImageInfo[]>media, title ?? '')
|
||||||
|
: [],
|
||||||
vendor: product.vendor,
|
vendor: product.vendor,
|
||||||
price: {
|
price: {
|
||||||
value: pricing[0]?.minPrice ?? 0,
|
value: pricing[0]?.minPrice ?? 0,
|
||||||
currencyCode: pricing[0]?.currency.code,
|
currencyCode: pricing[0]?.currency.code,
|
||||||
},
|
},
|
||||||
variants: variants?.length ? normalizeProductVariants(variants) : [],
|
variants: !!variants
|
||||||
options: variants?.length
|
? normalizeProductVariants(<CatalogProductVariant[]>variants)
|
||||||
? groupProductOptionsByAttributeLabel(variants)
|
: [],
|
||||||
|
options: !!variants
|
||||||
|
? groupProductOptionsByAttributeLabel(<CatalogProductVariant[]>variants)
|
||||||
: [],
|
: [],
|
||||||
...rest,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,19 +207,28 @@ export function normalizeCart(cart: ReactionCart): Cart {
|
|||||||
email: '',
|
email: '',
|
||||||
createdAt: cart.createdAt,
|
createdAt: cart.createdAt,
|
||||||
currency: {
|
currency: {
|
||||||
code: cart.checkout?.summary?.total?.currency.code,
|
code: cart.checkout?.summary?.total?.currency.code ?? '',
|
||||||
},
|
},
|
||||||
taxesIncluded: false,
|
taxesIncluded: false,
|
||||||
lineItems: cart.items?.edges?.map(normalizeLineItem),
|
lineItems:
|
||||||
lineItemsSubtotalPrice: +cart.checkout?.summary?.itemTotal?.amount,
|
cart.items?.edges?.map((cartItem) =>
|
||||||
subtotalPrice: +cart.checkout?.summary?.itemTotal?.amount,
|
normalizeLineItem(<CartItemEdge>cartItem)
|
||||||
totalPrice: cart.checkout?.summary?.total?.amount,
|
) ?? [],
|
||||||
|
lineItemsSubtotalPrice: +(cart.checkout?.summary?.itemTotal?.amount ?? 0),
|
||||||
|
subtotalPrice: +(cart.checkout?.summary?.itemTotal?.amount ?? 0),
|
||||||
|
totalPrice: cart.checkout?.summary?.total?.amount ?? 0,
|
||||||
discounts: [],
|
discounts: [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeLineItem({
|
function normalizeLineItem(cartItemEdge: CartItemEdge): LineItem {
|
||||||
node: {
|
const cartItem = cartItemEdge.node
|
||||||
|
|
||||||
|
if (!cartItem) {
|
||||||
|
return <LineItem>{}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
_id,
|
_id,
|
||||||
compareAtPrice,
|
compareAtPrice,
|
||||||
imageURLs,
|
imageURLs,
|
||||||
@ -179,9 +238,8 @@ function normalizeLineItem({
|
|||||||
optionTitle,
|
optionTitle,
|
||||||
variantTitle,
|
variantTitle,
|
||||||
quantity,
|
quantity,
|
||||||
},
|
} = <CartItem>cartItem
|
||||||
}: CartItemEdge): LineItem {
|
|
||||||
console.log('imageURLs', imageURLs)
|
|
||||||
return {
|
return {
|
||||||
id: _id,
|
id: _id,
|
||||||
variantId: String(productConfiguration?.productVariantId),
|
variantId: String(productConfiguration?.productVariantId),
|
||||||
@ -193,11 +251,12 @@ function normalizeLineItem({
|
|||||||
sku: String(productConfiguration?.productVariantId),
|
sku: String(productConfiguration?.productVariantId),
|
||||||
name: String(optionTitle || variantTitle),
|
name: String(optionTitle || variantTitle),
|
||||||
image: {
|
image: {
|
||||||
url: imageURLs?.original ?? '/product-img-placeholder.svg',
|
url: imageURLs?.thumbnail ?? '/product-img-placeholder.svg',
|
||||||
},
|
},
|
||||||
requiresShipping: true,
|
requiresShipping: true,
|
||||||
price: priceWhenAdded?.amount,
|
price: priceWhenAdded?.amount,
|
||||||
listPrice: compareAtPrice?.amount,
|
listPrice: compareAtPrice?.amount ?? 0,
|
||||||
|
options: [],
|
||||||
},
|
},
|
||||||
path: '',
|
path: '',
|
||||||
discounts: [],
|
discounts: [],
|
||||||
@ -211,12 +270,25 @@ function normalizeLineItem({
|
|||||||
|
|
||||||
export function normalizeCustomer(viewer: Account): Customer {
|
export function normalizeCustomer(viewer: Account): Customer {
|
||||||
if (!viewer) {
|
if (!viewer) {
|
||||||
return {}
|
return <Customer>{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return <Customer>{
|
||||||
firstName: viewer.firstName ?? '',
|
firstName: viewer.firstName ?? '',
|
||||||
lastName: viewer.lastName ?? '',
|
lastName: viewer.lastName ?? '',
|
||||||
email: viewer.primaryEmailAddress,
|
email: viewer.primaryEmailAddress,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function flatVariantOptions(variant: CatalogProductVariant): ProductVariant[] {
|
||||||
|
const variantOptions = <CatalogProductVariant[]>variant.options
|
||||||
|
|
||||||
|
return normalizeProductVariants(variantOptions).map((variantOption) => {
|
||||||
|
variantOption.options.push(normalizeProductOption(variant))
|
||||||
|
return variantOption
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function variantHasOptions(variant: CatalogProductVariant) {
|
||||||
|
return !!variant.options && variant.options.length != 0
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user