mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
Merge pull request #2 from CristianCucunuba/fix-types
fix types for normalize products
This commit is contained in:
commit
b125f9f577
@ -5,7 +5,6 @@ export interface CommerceAPIConfig {
|
|||||||
commerceUrl: string
|
commerceUrl: string
|
||||||
apiToken: string
|
apiToken: string
|
||||||
cartCookie: string
|
cartCookie: string
|
||||||
cartIdCookie: string
|
|
||||||
cartCookieMaxAge: number
|
cartCookieMaxAge: number
|
||||||
customerCookie: string
|
customerCookie: string
|
||||||
fetch<Data = any, Variables = any>(
|
fetch<Data = any, Variables = any>(
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
REACTION_STORE_DOMAIN=
|
||||||
|
REACTION_SHOP_ID=
|
@ -18,7 +18,14 @@ if (!API_URL) {
|
|||||||
|
|
||||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
||||||
|
|
||||||
export interface ReactionCommerceConfig extends CommerceAPIConfig {}
|
export interface ReactionCommerceConfig
|
||||||
|
extends Omit<CommerceAPIConfig, 'apiToken'> {
|
||||||
|
shopId: string
|
||||||
|
cartIdCookie: string
|
||||||
|
dummyEmptyCartId?: string
|
||||||
|
anonymousCartTokenCookie?: string
|
||||||
|
anonymousCartTokenCookieMaxAge?: number
|
||||||
|
}
|
||||||
|
|
||||||
export class Config {
|
export class Config {
|
||||||
private config: ReactionCommerceConfig
|
private config: ReactionCommerceConfig
|
||||||
@ -42,9 +49,11 @@ export class Config {
|
|||||||
const config = new Config({
|
const config = new Config({
|
||||||
locale: 'en-US',
|
locale: 'en-US',
|
||||||
commerceUrl: API_URL,
|
commerceUrl: API_URL,
|
||||||
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
cartCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
cartIdCookie: REACTION_CART_ID_COOKIE,
|
cartIdCookie: REACTION_CART_ID_COOKIE,
|
||||||
dummyEmptyCartId: REACTION_EMPTY_DUMMY_CART_ID,
|
dummyEmptyCartId: REACTION_EMPTY_DUMMY_CART_ID,
|
||||||
|
cartCookieMaxAge: REACTION_COOKIE_EXPIRE,
|
||||||
|
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
anonymousCartTokenCookieMaxAge: REACTION_COOKIE_EXPIRE,
|
anonymousCartTokenCookieMaxAge: REACTION_COOKIE_EXPIRE,
|
||||||
fetch: fetchGraphqlApi,
|
fetch: fetchGraphqlApi,
|
||||||
customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE,
|
customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE,
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
export const REACTION_ANONYMOUS_CART_TOKEN_COOKIE =
|
export const REACTION_ANONYMOUS_CART_TOKEN_COOKIE =
|
||||||
'reaction_anonymousCartToken'
|
'reaction_anonymousCartToken'
|
||||||
|
|
||||||
|
export const REACTION_CUSTOMER_TOKEN_COOKIE = 'reaction_customerToken'
|
||||||
|
|
||||||
export const REACTION_CART_ID_COOKIE = 'reaction_cartId'
|
export const REACTION_CART_ID_COOKIE = 'reaction_cartId'
|
||||||
|
|
||||||
export const REACTION_EMPTY_DUMMY_CART_ID = 'DUMMY_EMPTY_CART_ID'
|
export const REACTION_EMPTY_DUMMY_CART_ID = 'DUMMY_EMPTY_CART_ID'
|
||||||
|
|
||||||
export const REACTION_CUSTOMER_TOKEN_COOKIE = 'reaction_customerToken'
|
export const STORE_DOMAIN = process.env.NEXT_PUBLIC_REACTION_STORE_DOMAIN
|
||||||
|
|
||||||
export const REACTION_COOKIE_EXPIRE = 30
|
export const REACTION_COOKIE_EXPIRE = 30
|
||||||
|
|
||||||
export const API_URL = `http://127.0.0.1:3000/graphql`
|
export const API_URL = `http://${process.env.REACTION_STORE_DOMAIN}/graphql`
|
||||||
|
|
||||||
export const SHOP_ID = 'cmVhY3Rpb24vc2hvcDpIZGIycnRYTWVpbVRKbzZrcg=='
|
export const SHOP_ID = process.env.REACTION_SHOP_ID ?? ''
|
||||||
|
@ -8,18 +8,28 @@ import {
|
|||||||
} from '@commerce'
|
} from '@commerce'
|
||||||
|
|
||||||
import { reactionCommerceProvider, ReactionCommerceProvider } from './provider'
|
import { reactionCommerceProvider, ReactionCommerceProvider } from './provider'
|
||||||
import { REACTION_ANONYMOUS_CART_TOKEN_COOKIE, SHOP_ID } from './const'
|
import {
|
||||||
|
REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
|
SHOP_ID,
|
||||||
|
REACTION_CART_ID_COOKIE,
|
||||||
|
} from './const'
|
||||||
|
|
||||||
export { reactionCommerceProvider }
|
export { reactionCommerceProvider }
|
||||||
export type { ReactionCommerceProvider }
|
export type { ReactionCommerceProvider }
|
||||||
|
|
||||||
export const reactionCommerceConfig: CommerceConfig = {
|
type ReactionConfig = CommerceConfig & {
|
||||||
|
shopId: string
|
||||||
|
anonymousCartTokenCookie: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const reactionCommerceConfig: ReactionConfig = {
|
||||||
locale: 'en-us',
|
locale: 'en-us',
|
||||||
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
anonymousCartTokenCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
|
||||||
|
cartCookie: REACTION_CART_ID_COOKIE,
|
||||||
shopId: SHOP_ID,
|
shopId: SHOP_ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReactionCommerceConfig = Partial<CommerceConfig>
|
export type ReactionCommerceConfig = Partial<ReactionConfig>
|
||||||
|
|
||||||
export type ReactionCommerceProps = {
|
export type ReactionCommerceProps = {
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { GraphQLFetcherResult } from '@commerce/api'
|
import { GraphQLFetcherResult } from '@commerce/api'
|
||||||
import { getConfig, ReactionCommerceConfig } from '../api'
|
import { getConfig, ReactionCommerceConfig } from '../api'
|
||||||
import { CatalogItemEdge } from '../schema'
|
import { CatalogItemEdge, CatalogItemProduct } from '../schema'
|
||||||
import { catalogItemsQuery, normalizeProduct } from '../utils'
|
import { catalogItemsQuery, normalizeProduct } from '../utils'
|
||||||
import { Product } from '@commerce/types'
|
import { Product } from '@commerce/types'
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ type Variables = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ReturnType = {
|
type ReturnType = {
|
||||||
products: CatalogItemConnection[]
|
products: Product[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllProducts = async (options: {
|
const getAllProducts = async (options: {
|
||||||
@ -29,8 +29,8 @@ const getAllProducts = async (options: {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const catalogItems =
|
const catalogItems =
|
||||||
data.catalogItems?.edges?.map(({ node: p }: CatalogItemEdge) =>
|
data.catalogItems?.edges?.map(({ node: itemProduct }: CatalogItemEdge) =>
|
||||||
normalizeProduct(p)
|
normalizeProduct(itemProduct as CatalogItemProduct)
|
||||||
) ?? []
|
) ?? []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
import { Customer } from '@commerce/types'
|
import { Product, Customer } from '@commerce/types'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
CatalogItem,
|
|
||||||
Cart as ReactionCart,
|
Cart as ReactionCart,
|
||||||
ProductPricingInfo,
|
ProductPricingInfo,
|
||||||
CatalogProductVariant,
|
CatalogProductVariant,
|
||||||
CartItemEdge,
|
CartItemEdge,
|
||||||
|
CatalogItemProduct,
|
||||||
|
CatalogProduct,
|
||||||
|
ImageInfo,
|
||||||
|
Maybe,
|
||||||
} from '../schema'
|
} from '../schema'
|
||||||
|
|
||||||
import type { Cart, LineItem } from '../types'
|
import type { Cart, LineItem } from '../types'
|
||||||
|
|
||||||
|
type ProductOption = {
|
||||||
|
__typename?: string
|
||||||
|
id: string
|
||||||
|
displayName: string
|
||||||
|
values: any[]
|
||||||
|
}
|
||||||
|
|
||||||
const money = ({ displayPrice }: ProductPricingInfo) => {
|
const money = ({ displayPrice }: ProductPricingInfo) => {
|
||||||
return {
|
return {
|
||||||
displayPrice,
|
displayPrice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeProductOption = ({
|
const normalizeProductImages = (images: Maybe<ImageInfo>[], name: string) =>
|
||||||
id,
|
images.map((image) => ({
|
||||||
name: displayName,
|
url: image?.URLs?.original || image?.URLs?.medium || '',
|
||||||
values,
|
alt: name,
|
||||||
}: ProductOption) => {
|
}))
|
||||||
|
|
||||||
|
const normalizeProductOption = ({ id, displayName, values }: ProductOption) => {
|
||||||
return {
|
return {
|
||||||
__typename: 'MultipleChoiceOption',
|
__typename: 'MultipleChoiceOption',
|
||||||
id,
|
id,
|
||||||
@ -30,7 +42,7 @@ const normalizeProductOption = ({
|
|||||||
let output: any = {
|
let output: any = {
|
||||||
label: value,
|
label: value,
|
||||||
}
|
}
|
||||||
if (displayName === 'Color') {
|
if (displayName.toLowerCase() === 'color') {
|
||||||
output = {
|
output = {
|
||||||
...output,
|
...output,
|
||||||
hexColors: [value],
|
hexColors: [value],
|
||||||
@ -41,59 +53,39 @@ const normalizeProductOption = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeProductVariants = (variants: [CatalogProductVariant]) => {
|
const normalizeProductVariants = (variants: Maybe<CatalogProductVariant>[]) => {
|
||||||
return variants?.map(
|
return variants.map((variant) => {
|
||||||
({
|
const { _id, options, sku, title, pricing = [], variantId } = variant ?? {}
|
||||||
variantId,
|
const variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice ?? 0
|
||||||
attributeLabel,
|
|
||||||
optionTitle,
|
|
||||||
options,
|
|
||||||
sku,
|
|
||||||
title,
|
|
||||||
pricing,
|
|
||||||
}) => {
|
|
||||||
let variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice
|
|
||||||
|
|
||||||
if (variantPrice === undefined) {
|
|
||||||
variantPrice = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: variantId,
|
id: _id ?? '',
|
||||||
name: title,
|
name: title,
|
||||||
sku: sku ?? variantId,
|
sku: sku ?? variantId,
|
||||||
price: variantPrice,
|
price: variantPrice,
|
||||||
listPrice: pricing[0]?.compareAtPrice?.amount ?? variantPrice,
|
listPrice: pricing[0]?.compareAtPrice?.amount ?? variantPrice,
|
||||||
requiresShipping: true,
|
requiresShipping: true,
|
||||||
options:
|
options: options?.length
|
||||||
options?.map(
|
? options.map((option) => {
|
||||||
({ _id, attributeLabel, optionTitle }: CatalogProductVariant) =>
|
return normalizeProductOption({
|
||||||
normalizeProductOption({
|
id: option?._id ?? '',
|
||||||
id: _id,
|
displayName: option?.attributeLabel ?? '',
|
||||||
name: attributeLabel,
|
values: [option?.optionTitle],
|
||||||
values: [optionTitle],
|
|
||||||
})
|
})
|
||||||
) ?? [],
|
})
|
||||||
// options: [
|
: [],
|
||||||
// {
|
|
||||||
// __typename: 'MultipleChoiceOption',
|
|
||||||
// displayName: attributeLabel,
|
|
||||||
// values: [{ label: optionTitle }],
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupProductOptionsByAttributeLabel(
|
export function groupProductOptionsByAttributeLabel(
|
||||||
options: [CatalogProductVariant]
|
options: Maybe<CatalogProductVariant>[]
|
||||||
) {
|
) {
|
||||||
return options.reduce((groupedOptions, currentOption) => {
|
return options.reduce((groupedOptions, currentOption) => {
|
||||||
const attributeLabelIndex = groupedOptions.findIndex((option) => {
|
const attributeLabelIndex = groupedOptions.findIndex((option) => {
|
||||||
return (
|
return (
|
||||||
option.displayName.toLowerCase() ===
|
option.displayName.toLowerCase() ===
|
||||||
currentOption.attributeLabel.toLowerCase()
|
currentOption?.attributeLabel.toLowerCase()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -101,68 +93,61 @@ export function groupProductOptionsByAttributeLabel(
|
|||||||
groupedOptions[attributeLabelIndex].values = [
|
groupedOptions[attributeLabelIndex].values = [
|
||||||
...groupedOptions[attributeLabelIndex].values,
|
...groupedOptions[attributeLabelIndex].values,
|
||||||
{
|
{
|
||||||
label: currentOption.optionTitle,
|
label: currentOption?.optionTitle ?? '',
|
||||||
hexColors: [currentOption.optionTitle],
|
hexColors: [currentOption?.optionTitle] ?? '',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
groupedOptions = [
|
groupedOptions = [
|
||||||
...groupedOptions,
|
...groupedOptions,
|
||||||
normalizeProductOption({
|
normalizeProductOption({
|
||||||
id: currentOption.variantId,
|
id: currentOption?.variantId ?? '',
|
||||||
name: currentOption.attributeLabel,
|
displayName: currentOption?.attributeLabel ?? '',
|
||||||
values: [currentOption.optionTitle],
|
values: [currentOption?.optionTitle ?? ''],
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
return groupedOptions
|
return groupedOptions
|
||||||
}, [])
|
}, [] as ProductOption[])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeProduct(productNode: CatalogItemEdge): CatalogItem {
|
export function normalizeProduct(productNode: CatalogItemProduct): Product {
|
||||||
|
const product = productNode.product as CatalogProduct
|
||||||
|
|
||||||
const {
|
const {
|
||||||
_id,
|
_id,
|
||||||
product: {
|
|
||||||
productId,
|
productId,
|
||||||
|
title,
|
||||||
description,
|
description,
|
||||||
title: name,
|
|
||||||
vendor,
|
|
||||||
pricing,
|
|
||||||
slug,
|
slug,
|
||||||
primaryImage,
|
sku,
|
||||||
variants,
|
media,
|
||||||
},
|
pricing,
|
||||||
...rest
|
|
||||||
} = productNode
|
|
||||||
|
|
||||||
const product = {
|
|
||||||
id: productId ?? _id,
|
|
||||||
name,
|
|
||||||
vendor,
|
vendor,
|
||||||
description,
|
variants,
|
||||||
path: `/${slug}`,
|
...rest
|
||||||
slug: slug?.replace(/^\/+|\/+$/g, ''),
|
} = product
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: productId ?? _id,
|
||||||
|
name: title ?? '',
|
||||||
|
description: description ?? '',
|
||||||
|
slug: slug?.replace(/^\/+|\/+$/g, '') ?? '',
|
||||||
|
path: slug ?? '',
|
||||||
|
sku: sku ?? '',
|
||||||
|
images: media?.length ? normalizeProductImages(media, title ?? '') : [],
|
||||||
|
vendor: product.vendor,
|
||||||
price: {
|
price: {
|
||||||
value: pricing[0].minPrice,
|
value: pricing[0]?.price ?? 0,
|
||||||
currencyCode: pricing[0].currency.code,
|
currencyCode: pricing[0]?.currency.code,
|
||||||
},
|
},
|
||||||
variants: variants ? normalizeProductVariants(variants) : [],
|
variants: variants?.length ? normalizeProductVariants(variants) : [],
|
||||||
options: variants ? groupProductOptionsByAttributeLabel(variants) : [],
|
options: variants?.length
|
||||||
images: [],
|
? groupProductOptionsByAttributeLabel(variants)
|
||||||
|
: [],
|
||||||
...rest,
|
...rest,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (productNode.product.primaryImage) {
|
|
||||||
product.images = [
|
|
||||||
{
|
|
||||||
url: primaryImage?.URLs?.original,
|
|
||||||
alt: name,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
return product
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeCart(cart: ReactionCart): Cart {
|
export function normalizeCart(cart: ReactionCart): Cart {
|
||||||
|
@ -29,7 +29,7 @@ edges {
|
|||||||
minPrice
|
minPrice
|
||||||
maxPrice
|
maxPrice
|
||||||
}
|
}
|
||||||
primaryImage {
|
media {
|
||||||
URLs {
|
URLs {
|
||||||
thumbnail
|
thumbnail
|
||||||
small
|
small
|
||||||
|
Loading…
x
Reference in New Issue
Block a user