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