fix types for normalize products

This commit is contained in:
cristiancc 2021-04-07 13:15:41 -05:00
parent 49bd38fd82
commit d614e817c6
9 changed files with 114 additions and 113 deletions

View File

@ -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>(

View File

@ -1,2 +1,2 @@
SHOPIFY_STORE_DOMAIN= REACTION_STORE_DOMAIN=
SHOPIFY_STOREFRONT_ACCESS_TOKEN= REACTION_SHOP_ID=

View File

@ -5,8 +5,8 @@ import {
REACTION_ANONYMOUS_CART_TOKEN_COOKIE, REACTION_ANONYMOUS_CART_TOKEN_COOKIE,
REACTION_CART_ID_COOKIE, REACTION_CART_ID_COOKIE,
REACTION_EMPTY_DUMMY_CART_ID, REACTION_EMPTY_DUMMY_CART_ID,
SHOPIFY_CUSTOMER_TOKEN_COOKIE, REACTION_CUSTOMER_TOKEN_COOKIE,
SHOPIFY_COOKIE_EXPIRE, REACTION_COOKIE_EXPIRE,
SHOP_ID, SHOP_ID,
} from '../const' } from '../const'
@ -18,7 +18,11 @@ 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 CommerceAPIConfig {
shopId: string
cartIdCookie: string
dummyEmptyCartId: string
}
export class Config { export class Config {
private config: ReactionCommerceConfig private config: ReactionCommerceConfig
@ -42,12 +46,13 @@ export class Config {
const config = new Config({ const config = new Config({
locale: 'en-US', locale: 'en-US',
commerceUrl: API_URL, commerceUrl: API_URL,
apiToken: '',
cartCookie: 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: SHOPIFY_COOKIE_EXPIRE, cartCookieMaxAge: REACTION_COOKIE_EXPIRE,
fetch: fetchGraphqlApi, fetch: fetchGraphqlApi,
customerCookie: SHOPIFY_CUSTOMER_TOKEN_COOKIE, customerCookie: REACTION_CUSTOMER_TOKEN_COOKIE,
shopId: SHOP_ID, shopId: SHOP_ID,
}) })

View File

@ -1,18 +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 SHOPIFY_CHECKOUT_URL_COOKIE = 'shopify_checkoutUrl' export const STORE_DOMAIN = process.env.NEXT_PUBLIC_REACTION_STORE_DOMAIN
export const SHOPIFY_CUSTOMER_TOKEN_COOKIE = 'shopify_customerToken' export const REACTION_COOKIE_EXPIRE = 30
export const STORE_DOMAIN = process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN export const API_URL = `http://${process.env.REACTION_STORE_DOMAIN}/graphql`
export const SHOPIFY_COOKIE_EXPIRE = 30 export const SHOP_ID = process.env.REACTION_SHOP_ID ?? ''
export const API_URL = `http://127.0.0.1:3000/graphql`
export const SHOP_ID = 'cmVhY3Rpb24vc2hvcDplcnBESFlDdzc5cFRBV0FHUg=='

View File

@ -13,13 +13,17 @@ import { REACTION_ANONYMOUS_CART_TOKEN_COOKIE, SHOP_ID } from './const'
export { reactionCommerceProvider } export { reactionCommerceProvider }
export type { ReactionCommerceProvider } export type { ReactionCommerceProvider }
export const reactionCommerceConfig: CommerceConfig = { type ReactionConfig = CommerceConfig & {
shopId: string
}
export const reactionCommerceConfig: ReactionConfig = {
locale: 'en-us', locale: 'en-us',
cartCookie: REACTION_ANONYMOUS_CART_TOKEN_COOKIE, cartCookie: REACTION_ANONYMOUS_CART_TOKEN_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

View File

@ -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 } from '../utils/queries' import { catalogItemsQuery } from '../utils/queries'
import { normalizeProduct } from '../utils/normalize' import { normalizeProduct } from '../utils/normalize'
import { Product } from '@commerce/types' import { Product } from '@commerce/types'
@ -30,8 +30,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 {

View File

@ -1,20 +1,24 @@
import Cookies, { CookieAttributes } from 'js-cookie' import Cookies, { CookieAttributes } from 'js-cookie'
import { SHOPIFY_COOKIE_EXPIRE, SHOPIFY_CUSTOMER_TOKEN_COOKIE } from '../const' import {
REACTION_COOKIE_EXPIRE,
REACTION_CUSTOMER_TOKEN_COOKIE,
} from '../const'
export const getCustomerToken = () => Cookies.get(SHOPIFY_CUSTOMER_TOKEN_COOKIE) export const getCustomerToken = () =>
Cookies.get(REACTION_CUSTOMER_TOKEN_COOKIE)
export const setCustomerToken = ( export const setCustomerToken = (
token: string | null, token: string | null,
options?: CookieAttributes options?: CookieAttributes
) => { ) => {
if (!token) { if (!token) {
Cookies.remove(SHOPIFY_CUSTOMER_TOKEN_COOKIE) Cookies.remove(REACTION_CUSTOMER_TOKEN_COOKIE)
} else { } else {
Cookies.set( Cookies.set(
SHOPIFY_CUSTOMER_TOKEN_COOKIE, REACTION_CUSTOMER_TOKEN_COOKIE,
token, token,
options ?? { options ?? {
expires: SHOPIFY_COOKIE_EXPIRE, expires: REACTION_COOKIE_EXPIRE,
} }
) )
} }

View File

@ -1,26 +1,38 @@
import { Product } from '@commerce/types' import { Product } from '@commerce/types'
import { import {
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,
@ -29,7 +41,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],
@ -40,53 +52,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,
}) => {
const variantPrice = pricing[0]?.price ?? pricing[0]?.minPrice
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?.map(({ attributeLabel, optionTitle }: CatalogProductVariant) => options: options?.length
// normalizeProductOption({ ? options.map((option) => {
// id: _id, return normalizeProductOption({
// name: attributeLabel, id: option?._id ?? '',
// values: [optionTitle], displayName: option?.attributeLabel ?? '',
// }) values: [option?.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()
) )
}) })
@ -94,68 +92,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 {

View File

@ -29,7 +29,7 @@ edges {
minPrice minPrice
maxPrice maxPrice
} }
primaryImage { media {
URLs { URLs {
thumbnail thumbnail
small small