forked from crowetic/commerce
Match product options with variants
This commit is contained in:
parent
8a8ef7dbba
commit
dd40b8c604
@ -1,5 +1,4 @@
|
|||||||
import { getConfig, SwellConfig } from '../api'
|
import { getConfig, SwellConfig } from '../api'
|
||||||
import getPageQuery from '../utils/queries/get-page-query'
|
|
||||||
import { Page } from './get-all-pages'
|
import { Page } from './get-all-pages'
|
||||||
|
|
||||||
type Variables = {
|
type Variables = {
|
||||||
|
197
framework/swell/schema.d.ts
vendored
197
framework/swell/schema.d.ts
vendored
@ -321,96 +321,113 @@ export enum CardBrand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** A container for all the information required to checkout items and pay. */
|
/** A container for all the information required to checkout items and pay. */
|
||||||
export type Checkout = Node & {
|
export type Checkout = {
|
||||||
__typename?: 'Checkout'
|
name: string
|
||||||
/** The gift cards used on the checkout. */
|
currency: string
|
||||||
appliedGiftCards: Array<AppliedGiftCard>
|
support_email: string
|
||||||
/**
|
fields: any[]
|
||||||
* The available shipping rates for this Checkout.
|
scripts: any[]
|
||||||
* Should only be used when checkout `requiresShipping` is `true` and
|
accounts: string
|
||||||
* the shipping address is valid.
|
email_optin: boolean
|
||||||
*/
|
terms_policy?: string
|
||||||
availableShippingRates?: Maybe<AvailableShippingRates>
|
refund_policy?: string
|
||||||
/** The date and time when the checkout was completed. */
|
privacy_policy?: string
|
||||||
completedAt?: Maybe<Scalars['DateTime']>
|
theme?: stirng
|
||||||
/** The date and time when the checkout was created. */
|
countries: any[]
|
||||||
createdAt: Scalars['DateTime']
|
currencies: any[]
|
||||||
/** The currency code for the Checkout. */
|
payment_methods: any[]
|
||||||
currencyCode: CurrencyCode
|
coupons: boolean
|
||||||
/** A list of extra information that is added to the checkout. */
|
giftcards: boolean
|
||||||
customAttributes: Array<Attribute>
|
|
||||||
/**
|
// __typename?: 'Checkout'
|
||||||
* The customer associated with the checkout.
|
// /** The gift cards used on the checkout. */
|
||||||
* @deprecated This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it.
|
// appliedGiftCards: Array<AppliedGiftCard>
|
||||||
*/
|
// /**
|
||||||
customer?: Maybe<Customer>
|
// * The available shipping rates for this Checkout.
|
||||||
/** Discounts that have been applied on the checkout. */
|
// * Should only be used when checkout `requiresShipping` is `true` and
|
||||||
discountApplications: DiscountApplicationConnection
|
// * the shipping address is valid.
|
||||||
/** The email attached to this checkout. */
|
// */
|
||||||
email?: Maybe<Scalars['String']>
|
// availableShippingRates?: Maybe<AvailableShippingRates>
|
||||||
/** Globally unique identifier. */
|
// /** The date and time when the checkout was completed. */
|
||||||
id: Scalars['ID']
|
// completedAt?: Maybe<Scalars['DateTime']>
|
||||||
/** A list of line item objects, each one containing information about an item in the checkout. */
|
// /** The date and time when the checkout was created. */
|
||||||
lineItems: CheckoutLineItemConnection
|
// createdAt: Scalars['DateTime']
|
||||||
/** The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. */
|
// /** The currency code for the Checkout. */
|
||||||
lineItemsSubtotalPrice: MoneyV2
|
// currencyCode: CurrencyCode
|
||||||
/** The note associated with the checkout. */
|
// /** A list of extra information that is added to the checkout. */
|
||||||
note?: Maybe<Scalars['String']>
|
// customAttributes: Array<Attribute>
|
||||||
/** The resulting order from a paid checkout. */
|
// /**
|
||||||
order?: Maybe<Order>
|
// * The customer associated with the checkout.
|
||||||
/** The Order Status Page for this Checkout, null when checkout is not completed. */
|
// * @deprecated This field will always return null. If you have an authentication token for the customer, you can use the `customer` field on the query root to retrieve it.
|
||||||
orderStatusUrl?: Maybe<Scalars['URL']>
|
// */
|
||||||
/**
|
// customer?: Maybe<Customer>
|
||||||
* The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards.
|
// /** Discounts that have been applied on the checkout. */
|
||||||
* @deprecated Use `paymentDueV2` instead
|
// discountApplications: DiscountApplicationConnection
|
||||||
*/
|
// /** The email attached to this checkout. */
|
||||||
paymentDue: Scalars['Money']
|
// email?: Maybe<Scalars['String']>
|
||||||
/** The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. */
|
// /** Globally unique identifier. */
|
||||||
paymentDueV2: MoneyV2
|
// id: Scalars['ID']
|
||||||
/**
|
// /** A list of line item objects, each one containing information about an item in the checkout. */
|
||||||
* Whether or not the Checkout is ready and can be completed. Checkouts may
|
// lineItems: CheckoutLineItemConnection
|
||||||
* have asynchronous operations that can take time to finish. If you want
|
// /** The sum of all the prices of all the items in the checkout. Duties, taxes, shipping and discounts excluded. */
|
||||||
* to complete a checkout or ensure all the fields are populated and up to
|
// lineItemsSubtotalPrice: MoneyV2
|
||||||
* date, polling is required until the value is true.
|
// /** The note associated with the checkout. */
|
||||||
*/
|
// note?: Maybe<Scalars['String']>
|
||||||
ready: Scalars['Boolean']
|
// /** The resulting order from a paid checkout. */
|
||||||
/** States whether or not the fulfillment requires shipping. */
|
// order?: Maybe<Order>
|
||||||
requiresShipping: Scalars['Boolean']
|
// /** The Order Status Page for this Checkout, null when checkout is not completed. */
|
||||||
/** The shipping address to where the line items will be shipped. */
|
// orderStatusUrl?: Maybe<Scalars['URL']>
|
||||||
shippingAddress?: Maybe<MailingAddress>
|
// /**
|
||||||
/** The discounts that have been allocated onto the shipping line by discount applications. */
|
// * The amount left to be paid. This is equal to the cost of the line items, taxes and shipping minus discounts and gift cards.
|
||||||
shippingDiscountAllocations: Array<DiscountAllocation>
|
// * @deprecated Use `paymentDueV2` instead
|
||||||
/** Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. */
|
// */
|
||||||
shippingLine?: Maybe<ShippingRate>
|
// paymentDue: Scalars['Money']
|
||||||
/**
|
// /** The amount left to be paid. This is equal to the cost of the line items, duties, taxes and shipping minus discounts and gift cards. */
|
||||||
* Price of the checkout before shipping and taxes.
|
// paymentDueV2: MoneyV2
|
||||||
* @deprecated Use `subtotalPriceV2` instead
|
// /**
|
||||||
*/
|
// * Whether or not the Checkout is ready and can be completed. Checkouts may
|
||||||
subtotalPrice: Scalars['Money']
|
// * have asynchronous operations that can take time to finish. If you want
|
||||||
/** Price of the checkout before duties, shipping and taxes. */
|
// * to complete a checkout or ensure all the fields are populated and up to
|
||||||
subtotalPriceV2: MoneyV2
|
// * date, polling is required until the value is true.
|
||||||
/** Specifies if the Checkout is tax exempt. */
|
// */
|
||||||
taxExempt: Scalars['Boolean']
|
// ready: Scalars['Boolean']
|
||||||
/** Specifies if taxes are included in the line item and shipping line prices. */
|
// /** States whether or not the fulfillment requires shipping. */
|
||||||
taxesIncluded: Scalars['Boolean']
|
// requiresShipping: Scalars['Boolean']
|
||||||
/**
|
// /** The shipping address to where the line items will be shipped. */
|
||||||
* The sum of all the prices of all the items in the checkout, taxes and discounts included.
|
// shippingAddress?: Maybe<MailingAddress>
|
||||||
* @deprecated Use `totalPriceV2` instead
|
// /** The discounts that have been allocated onto the shipping line by discount applications. */
|
||||||
*/
|
// shippingDiscountAllocations: Array<DiscountAllocation>
|
||||||
totalPrice: Scalars['Money']
|
// /** Once a shipping rate is selected by the customer it is transitioned to a `shipping_line` object. */
|
||||||
/** The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. */
|
// shippingLine?: Maybe<ShippingRate>
|
||||||
totalPriceV2: MoneyV2
|
// /**
|
||||||
/**
|
// * Price of the checkout before shipping and taxes.
|
||||||
* The sum of all the taxes applied to the line items and shipping lines in the checkout.
|
// * @deprecated Use `subtotalPriceV2` instead
|
||||||
* @deprecated Use `totalTaxV2` instead
|
// */
|
||||||
*/
|
// subtotalPrice: Scalars['Money']
|
||||||
totalTax: Scalars['Money']
|
// /** Price of the checkout before duties, shipping and taxes. */
|
||||||
/** The sum of all the taxes applied to the line items and shipping lines in the checkout. */
|
// subtotalPriceV2: MoneyV2
|
||||||
totalTaxV2: MoneyV2
|
// /** Specifies if the Checkout is tax exempt. */
|
||||||
/** The date and time when the checkout was last updated. */
|
// taxExempt: Scalars['Boolean']
|
||||||
updatedAt: Scalars['DateTime']
|
// /** Specifies if taxes are included in the line item and shipping line prices. */
|
||||||
/** The url pointing to the checkout accessible from the web. */
|
// taxesIncluded: Scalars['Boolean']
|
||||||
webUrl: Scalars['URL']
|
// /**
|
||||||
|
// * The sum of all the prices of all the items in the checkout, taxes and discounts included.
|
||||||
|
// * @deprecated Use `totalPriceV2` instead
|
||||||
|
// */
|
||||||
|
// totalPrice: Scalars['Money']
|
||||||
|
// /** The sum of all the prices of all the items in the checkout, duties, taxes and discounts included. */
|
||||||
|
// totalPriceV2: MoneyV2
|
||||||
|
// /**
|
||||||
|
// * The sum of all the taxes applied to the line items and shipping lines in the checkout.
|
||||||
|
// * @deprecated Use `totalTaxV2` instead
|
||||||
|
// */
|
||||||
|
// totalTax: Scalars['Money']
|
||||||
|
// /** The sum of all the taxes applied to the line items and shipping lines in the checkout. */
|
||||||
|
// totalTaxV2: MoneyV2
|
||||||
|
// /** The date and time when the checkout was last updated. */
|
||||||
|
// updatedAt: Scalars['DateTime']
|
||||||
|
// /** The url pointing to the checkout accessible from the web. */
|
||||||
|
// webUrl: Scalars['URL']
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A container for all the information required to checkout items and pay. */
|
/** A container for all the information required to checkout items and pay. */
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import * as Core from '@commerce/types'
|
import * as Core from '@commerce/types'
|
||||||
import { CheckoutLineItem } from './schema'
|
import { CheckoutLineItem } from './schema'
|
||||||
|
|
||||||
|
export type SwellImage = {
|
||||||
|
file: {
|
||||||
|
url: String
|
||||||
|
height: Number
|
||||||
|
width: Number
|
||||||
|
}
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
export type SwellCart = {
|
export type SwellCart = {
|
||||||
id: string
|
id: string
|
||||||
account_id: number
|
account_id: number
|
||||||
@ -21,9 +30,28 @@ export type SwellCart = {
|
|||||||
// TODO: add missing fields
|
// TODO: add missing fields
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VariantResult = {
|
export type SwellVariant = {
|
||||||
id: string
|
id: string
|
||||||
option_value_ids: string[]
|
option_value_ids: string[]
|
||||||
|
name: string
|
||||||
|
price?: number
|
||||||
|
stock_status?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProductOptionValue {
|
||||||
|
label: string
|
||||||
|
hexColors?: string[]
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProductOptions = {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
variant: boolean
|
||||||
|
values: ProductOptionValue[]
|
||||||
|
required: boolean
|
||||||
|
active: boolean
|
||||||
|
attribute_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SwellProduct {
|
export interface SwellProduct {
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import { Product } from '@commerce/types'
|
import { Product, Customer } from '@commerce/types'
|
||||||
import { Customer } from '@commerce/types'
|
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Product as ShopifyProduct,
|
|
||||||
Checkout,
|
Checkout,
|
||||||
CheckoutLineItemEdge,
|
CheckoutLineItemEdge,
|
||||||
SelectedOption,
|
|
||||||
ImageConnection,
|
|
||||||
ProductVariantConnection,
|
|
||||||
MoneyV2,
|
MoneyV2,
|
||||||
ProductOption,
|
ProductOption,
|
||||||
} from '../schema'
|
} from '../schema'
|
||||||
|
|
||||||
import type { Cart, LineItem, SwellCustomer, SwellProduct } from '../types'
|
import type {
|
||||||
|
Cart,
|
||||||
|
LineItem,
|
||||||
|
SwellCustomer,
|
||||||
|
SwellProduct,
|
||||||
|
SwellImage,
|
||||||
|
SwellVariant,
|
||||||
|
ProductOptionValue,
|
||||||
|
} from '../types'
|
||||||
|
|
||||||
const money = ({ amount, currencyCode }: MoneyV2) => {
|
const money = ({ amount, currencyCode }: MoneyV2) => {
|
||||||
return {
|
return {
|
||||||
@ -22,15 +25,22 @@ const money = ({ amount, currencyCode }: MoneyV2) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type normalizedProductOption = {
|
||||||
|
__typename?: string
|
||||||
|
id: string
|
||||||
|
displayName: string
|
||||||
|
values: ProductOptionValue[]
|
||||||
|
}
|
||||||
|
|
||||||
const normalizeProductOption = ({
|
const normalizeProductOption = ({
|
||||||
id,
|
id,
|
||||||
name: displayName,
|
name: displayName = '',
|
||||||
values,
|
values,
|
||||||
}: ProductOption) => {
|
}: ProductOption) => {
|
||||||
let returnValues = values.map((value) => {
|
let returnValues = values.map((value) => {
|
||||||
let output: any = {
|
let output: any = {
|
||||||
displayName,
|
|
||||||
label: value.name,
|
label: value.name,
|
||||||
|
id: value?.id || id,
|
||||||
}
|
}
|
||||||
if (displayName === 'Color') {
|
if (displayName === 'Color') {
|
||||||
output = {
|
output = {
|
||||||
@ -48,50 +58,52 @@ const normalizeProductOption = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SwellImage = {
|
const normalizeProductImages = (images: SwellImage[]) => {
|
||||||
file: {
|
|
||||||
url: String
|
|
||||||
height: Number
|
|
||||||
width: Number
|
|
||||||
}
|
|
||||||
id: string
|
|
||||||
}
|
|
||||||
const normalizeProductImages = (images) => {
|
|
||||||
if (!images) {
|
if (!images) {
|
||||||
return [{ url: '/' }]
|
return [{ url: '/' }]
|
||||||
}
|
}
|
||||||
return images?.map(({ file, ...rest }: SwellImage) => ({
|
return images?.map(({ file, ...rest }: SwellImage) => ({
|
||||||
url: file?.url,
|
url: file?.url + '',
|
||||||
height: file?.height,
|
height: Number(file?.height),
|
||||||
width: file?.width,
|
width: Number(file?.width),
|
||||||
...rest,
|
...rest,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizeProductVariants = (variants) => {
|
const normalizeProductVariants = (
|
||||||
return variants?.map(({ id, name, price, sku }) => {
|
variants: SwellVariant[],
|
||||||
const values = name
|
productOptions: normalizedProductOption[]
|
||||||
.split(',')
|
) => {
|
||||||
.map((i) => ({ name: i.trim(), label: i.trim() }))
|
return variants?.map(
|
||||||
|
({ id, name, price, option_value_ids: optionValueIds }) => {
|
||||||
|
const values = name
|
||||||
|
.split(',')
|
||||||
|
.map((i) => ({ name: i.trim(), label: i.trim() }))
|
||||||
|
|
||||||
const options = values.map((value) => {
|
const options = optionValueIds.map((id) => {
|
||||||
return normalizeProductOption({
|
const matchingOption = productOptions.find((option) => {
|
||||||
|
return option.values.find(
|
||||||
|
(value: ProductOptionValue) => value.id == id
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return normalizeProductOption({
|
||||||
|
id,
|
||||||
|
name: matchingOption?.displayName ?? '',
|
||||||
|
values,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
values: [value],
|
// sku: sku ?? id,
|
||||||
})
|
price: price ?? null,
|
||||||
})
|
listPrice: price ?? null,
|
||||||
|
// requiresShipping: true,
|
||||||
return {
|
options,
|
||||||
id,
|
}
|
||||||
name,
|
|
||||||
sku: sku ?? id,
|
|
||||||
price: price ?? null,
|
|
||||||
listPrice: price ?? null,
|
|
||||||
// requiresShipping: true,
|
|
||||||
options,
|
|
||||||
}
|
}
|
||||||
})
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeProduct(swellProduct: SwellProduct): Product {
|
export function normalizeProduct(swellProduct: SwellProduct): Product {
|
||||||
@ -108,10 +120,10 @@ export function normalizeProduct(swellProduct: SwellProduct): Product {
|
|||||||
const productOptions = options
|
const productOptions = options
|
||||||
? options.map((o) => normalizeProductOption(o))
|
? options.map((o) => normalizeProductOption(o))
|
||||||
: []
|
: []
|
||||||
const productVariants = variants ? normalizeProductVariants(variants) : []
|
const productVariants = variants
|
||||||
|
? normalizeProductVariants(variants, productOptions)
|
||||||
|
: []
|
||||||
|
|
||||||
// ProductView.tsx assumes the existence of at least one product variant
|
|
||||||
const emptyVariants = [{ options: [{ id: 123 }] }]
|
|
||||||
const productImages = normalizeProductImages(images)
|
const productImages = normalizeProductImages(images)
|
||||||
const product = {
|
const product = {
|
||||||
...swellProduct,
|
...swellProduct,
|
||||||
@ -120,10 +132,7 @@ export function normalizeProduct(swellProduct: SwellProduct): Product {
|
|||||||
vendor: '',
|
vendor: '',
|
||||||
path: `/${slug}`,
|
path: `/${slug}`,
|
||||||
images: productImages,
|
images: productImages,
|
||||||
variants:
|
variants: productVariants,
|
||||||
productVariants && productVariants.length
|
|
||||||
? productVariants
|
|
||||||
: emptyVariants,
|
|
||||||
options: productOptions,
|
options: productOptions,
|
||||||
price: {
|
price: {
|
||||||
value,
|
value,
|
||||||
@ -167,12 +176,12 @@ function normalizeLineItem({
|
|||||||
}: CheckoutLineItemEdge): LineItem {
|
}: CheckoutLineItemEdge): LineItem {
|
||||||
const item = {
|
const item = {
|
||||||
id,
|
id,
|
||||||
variantId: String(variant?.id),
|
variantId: variant?.id ?? '',
|
||||||
productId: String(product?.id),
|
productId: product?.id ?? '',
|
||||||
name: product?.name ?? '',
|
name: product?.name ?? '',
|
||||||
quantity,
|
quantity,
|
||||||
variant: {
|
variant: {
|
||||||
id: String(variant?.id),
|
id: variant?.id ?? '',
|
||||||
sku: variant?.sku ?? '',
|
sku: variant?.sku ?? '',
|
||||||
name: variant?.name!,
|
name: variant?.name!,
|
||||||
image: {
|
image: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user