From 3c23854896300fe2c4ee9dfb259a4cb3dd7774f8 Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 14:15:19 +0300 Subject: [PATCH 01/28] feat(spree): add checkout and customer types for commerce integration --- .../spree/src/checkout/use-checkout.tsx | 19 ++ .../src/commerce/checkout/use-checkout.ts | 34 +++ .../commerce/checkout/use-submit-checkout.tsx | 21 ++ .../spree/src/commerce/types/cart.ts | 265 ++++++++++++++++++ .../spree/src/commerce/types/checkout.ts | 89 ++++++ .../spree/src/commerce/types/common.ts | 36 +++ .../src/commerce/types/customer/address.ts | 122 ++++++++ .../spree/src/commerce/types/customer/card.ts | 138 +++++++++ .../src/commerce/types/customer/index.ts | 54 ++++ .../src/commerce/utils/default-fetcher.ts | 12 + .../src/commerce/utils/define-property.ts | 37 +++ .../spree/src/commerce/utils/types.ts | 147 ++++++++++ .../spree/src/commerce/utils/use-data.tsx | 78 ++++++ .../spree/src/commerce/utils/use-hook.ts | 50 ++++ 14 files changed, 1102 insertions(+) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/cart.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/common.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/card.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/index.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/default-fetcher.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/define-property.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx new file mode 100644 index 00000000000..bd8e3ac755e --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -0,0 +1,19 @@ +import { SWRHook } from '@vercel/commerce/utils/types' +import useCheckout, { + UseCheckout, +} from '@vercel/commerce/checkout/use-checkout' + +export default useCheckout as UseCheckout + +export const handler: SWRHook = { + // Provide fetchOptions for SWR cache key + fetchOptions: { + // TODO: Revise url and query + url: 'checkout', + query: 'show', + }, + async fetcher({ input, options, fetch }) {}, + useHook: + ({ useData }) => + async (input) => ({}), +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts new file mode 100644 index 00000000000..110add9b11a --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -0,0 +1,34 @@ +import type { SWRHook, HookFetcherFn } from '@plasmicpkgs/commerce' +import type { GetCheckoutHook } from '../types/checkout' + +import Cookies from 'js-cookie' + +import { useHook, useSWRHook } from '../utils/use-hook' +import { Provider, useCommerce } from '@plasmicpkgs/commerce' + +export type UseCheckout< + H extends SWRHook = SWRHook +> = ReturnType + +export const fetcher: HookFetcherFn = async ({ + options, + input: { cartId }, + fetch, +}) => { + return cartId ? await fetch(options) : null +} + +const fn = (provider: Provider) => provider.checkout?.useCheckout! + +const useCheckout: UseCheckout = (input) => { + const hook = useHook(fn) + const { cartCookie } = useCommerce() + const fetcherFn = hook.fetcher ?? fetcher + const wrapper: typeof fetcher = (context) => { + context.input.cartId = Cookies.get(cartCookie) + return fetcherFn(context) + } + return useSWRHook({ ...hook, fetcher: wrapper })(input) +} + +export default useCheckout diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx new file mode 100644 index 00000000000..b5219c22e7f --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx @@ -0,0 +1,21 @@ +import type { HookFetcherFn, MutationHook } from '../utils/types' +import type { SubmitCheckoutHook } from '../types/checkout' +import type { Provider } from '@plasmicpkgs/commerce' + +import { useHook, useMutationHook } from '../utils/use-hook' +import { mutationFetcher } from '../utils/default-fetcher' + +export type UseSubmitCheckout< + H extends MutationHook = MutationHook +> = ReturnType + +export const fetcher: HookFetcherFn = mutationFetcher + +const fn = (provider: Provider) => provider.checkout?.useSubmitCheckout! + +const useSubmitCheckout: UseSubmitCheckout = (...args) => { + const hook = useHook(fn) + return useMutationHook({ fetcher, ...hook })(...args) +} + +export default useSubmitCheckout diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/cart.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/cart.ts new file mode 100644 index 00000000000..014fed87335 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/cart.ts @@ -0,0 +1,265 @@ +import type { Discount, Image, Measurement } from './common' + +// TODO: This should use the same type as the `ProductVariant` type from `product.ts` +export interface ProductVariant { + /** + * The unique identifier for the variant. + */ + id: string + /** + * The SKU (stock keeping unit) associated with the product variant. + */ + sku?: string + /** + * The product variant’s name, or the product's name. + */ + name: string + /** + * The product variant’s price after all discounts are applied. + */ + price: number + /** + * The product variant’s price before discounts are applied. + */ + listPrice: number + /** + * Indicates if the variant is available for sale. + */ + availableForSale?: boolean + /** + * Whether a customer needs to provide a shipping address when placing + * an order for the product variant. + */ + requiresShipping?: boolean + /** + * The image associated with the variant. + */ + image?: Image + /** + * The variant's weight. If a weight was not explicitly specified on the + * variant, this will be the product's weight. + */ + weight?: Measurement + /** + * The variant's height. If a height was not explicitly specified on the + * variant, this will be the product's height. + */ + height?: Measurement + /** + * The variant's width. If a width was not explicitly specified on the + * variant, this will be the product's width. + */ + width?: Measurement + /** + * The variant's depth. If a depth was not explicitly specified on the + * variant, this will be the product's depth. + */ + depth?: Measurement +} + +export interface SelectedOption { + /** + * The unique identifier for the option. + */ + id?: string + /** + * The product option’s name, such as "Color" or "Size". + */ + name: string + /** + * The product option’s value, such as "Red" or "XL". + */ + value: string +} + +export interface LineItem { + /** + * The unique identifier for the line item. + */ + id: string + /** + * The unique identifier for the product variant. + */ + variantId: string + /** + * The unique identifier for the product, if the variant is not provided. + */ + productId: string + /** + * This is usually the product's name. + */ + name: string + /** + * The quantity of the product variant in the line item. + */ + quantity: number + /** + * List of discounts applied to the line item. + */ + discounts: Discount[] + /** + * A human-friendly unique string automatically generated from the product’s name. + */ + path: string + /** + * The product variant. + */ + variant: ProductVariant + /** + * List of selected options, to be used when displaying the line item, such as Color: Red, Size: XL. + */ + options?: SelectedOption[] +} + +/** + * Shopping cart, a.k.a Checkout + */ +export interface Cart { + /** + * The unique identifier for the cart. + */ + id: string + /** + * ID of the customer to which the cart belongs. + */ + customerId?: string + /** + * The URL of the cart. + */ + url?: string + /** + * The email assigned to this cart. + */ + email?: string + /** + * The date and time when the cart was created. + */ + createdAt: string + /** + * The currency used for this cart */ + currency: { code: string } + /** + * Indicates if taxes are included in the line items. + */ + taxesIncluded: boolean + /** + * List of cart line items. + */ + lineItems: LineItem[] + /** + * The sum of all the pricexs of all the items in the cart. + * Duties, taxes, shipping and discounts excluded. + */ + lineItemsSubtotalPrice: number + /** + * Price of the cart before duties, shipping and taxes.*/ + subtotalPrice: number + /** + * The sum of all the prices of all the items in the cart. + * Duties, taxes and discounts included. + */ + totalPrice: number + /** + * Discounts that have been applied on the cart. + */ + discounts?: Discount[] +} + +/** + * Base cart item body used for cart mutations + */ +export interface CartItemBody { + /** + * The unique identifier for the product variant. + */ + variantId: string + /** + * The unique identifier for the product, if the variant is not provided. + */ + productId?: string + /** + * The quantity of the product variant. + */ + quantity?: number + + /** + * The product variant's selected options. + */ + optionsSelected?: SelectedOption[] +} + +/** + * Cart Hooks for add, update and remove items from the cart + */ +export type CartHooks = { + getCart: GetCartHook + addItem: AddItemHook + updateItem: UpdateItemHook + removeItem: RemoveItemHook +} + +export type GetCartHook = { + data: Cart | null | undefined + input: {} + fetcherInput: { cartId?: string } + swrState: { isEmpty: boolean } +} + +export type AddItemHook = { + data: Cart | null | undefined + input?: CartItemBody + fetcherInput: CartItemBody + body: { item: CartItemBody } + actionInput: CartItemBody +} + +export type UpdateItemHook = { + data: Cart | null | undefined + input: { item?: LineItem; wait?: number } + fetcherInput: { itemId: string; item: CartItemBody } + body: { itemId: string; item: CartItemBody } + actionInput: CartItemBody & { id: string } +} + +export type RemoveItemHook = { + data: Cart | null | undefined + input: { item?: LineItem } + fetcherInput: { itemId: string } + body: { itemId: string } + actionInput: { id: string } +} + +/** + * Cart API endpoitns & handlers for add, update and remove items from the cart + */ +export type CartSchema = { + endpoint: { + options: {} + handlers: CartHandlers + } +} + +export type CartHandlers = { + getCart: GetCartHandler + addItem: AddItemHandler + updateItem: UpdateItemHandler + removeItem: RemoveItemHandler +} + +export type GetCartHandler = GetCartHook & { + body: { cartId?: string } +} + +export type AddItemHandler = AddItemHook & { + data: Cart | null | undefined + body: { cartId?: string } +} + +export type UpdateItemHandler = UpdateItemHook & { + data: Cart + body: { cartId: string } +} + +export type RemoveItemHandler = RemoveItemHook & { + body: { cartId: string } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts new file mode 100644 index 00000000000..326af252e12 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -0,0 +1,89 @@ +import type { UseSubmitCheckout } from '../checkout/use-submit-checkout' +import type { AddressFields } from './customer/address' +import type { Card, CardFields } from './customer/card' +import type { LineItem } from './cart' + +export interface Checkout { + /** + * Indicates if the checkout has payment iformation collected. + */ + hasPayment: boolean + /** + * Indicates if the checkout has shipping information collected. + */ + hasShipping: boolean + /** + * The unique identifier for the address that the customer has selected for shipping. + */ + addressId: string + /** + * The list of payment cards that the customer has available. + */ + payments?: Card[] + /** + * The unique identifier of the card that the customer has selected for payment. + */ + cardId?: string + /** + * List of items in the checkout. + */ + lineItems?: LineItem[] +} + +export interface CheckoutBody { + /** + * The unique identifier for the cart. + */ + cartId?: string + /** + * The Card information. + * @see CardFields + */ + card: CardFields + /** + * The Address information. + * @see AddressFields + */ + address: AddressFields +} + +export type SubmitCheckoutHook = { + data: Checkout | null + input?: CheckoutBody + fetcherInput: CheckoutBody + body: { item: CheckoutBody } + actionInput: CheckoutBody +} + +export type GetCheckoutHook = { + data: Checkout | null + input: {} + fetcherInput: { cartId?: string } + swrState: { isEmpty: boolean } + mutations: { submit: UseSubmitCheckout } +} + +export type CheckoutHooks = { + submitCheckout?: SubmitCheckoutHook + getCheckout: GetCheckoutHook +} + +export type GetCheckoutHandler = GetCheckoutHook & { + body: { cartId?: string } +} + +export type SubmitCheckoutHandler = SubmitCheckoutHook & { + body: { cartId: string } +} + +export type CheckoutHandlers = { + getCheckout: GetCheckoutHandler + submitCheckout?: SubmitCheckoutHandler +} + +export type CheckoutSchema = { + endpoint: { + options: {} + handlers: CheckoutHandlers + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/common.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/common.ts new file mode 100644 index 00000000000..d63dfc0b988 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/common.ts @@ -0,0 +1,36 @@ +export interface Discount { + /** + * The value of the discount, can be an amount or percentage. + */ + value: number +} + +export interface Measurement { + /** + * The measurement's value. + */ + value: number + /** + * The measurement's unit, such as "KILOGRAMS", "GRAMS", "POUNDS" & "OOUNCES". + */ + unit: 'KILOGRAMS' | 'GRAMS' | 'POUNDS' | 'OUNCES' +} + +export interface Image { + /** + * The URL of the image. + */ + url: string + /** + * A word or phrase that describes the content of an image. + */ + alt?: string + /** + * The image's width. + */ + width?: number + /** + * The image's height. + */ + height?: number +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts new file mode 100644 index 00000000000..e6b71ff52c4 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts @@ -0,0 +1,122 @@ +export interface Address { + /** + * The unique identifier for the address. + */ + id: string + /** + * The customer's first name. + */ + mask: string +} + +export interface AddressFields { + /** + * The type of address. + * @example "billing, shipping" + */ + type: string + /** + * The customer's first name. + */ + firstName: string + /** + * The customer's last name. + */ + lastName: string + /** + * Company name. + */ + company: string + /** + * The customer's billing address street number. + */ + streetNumber: string + /** + * The customer's billing address apartment number. + */ + apartments: string + /** + * The customer's billing address zip code. + */ + zipCode: string + /** + * The customer's billing address city. + */ + city: string + /** + * The customer's billing address country. + */ + country: string +} + +/** + * Hooks for managing a customer's addresses. + */ + +export type GetAddressesHook = { + data: Address[] | null + input: {} + fetcherInput: { cartId?: string } + swrState: { isEmpty: boolean } +} + +export type AddItemHook = { + data: Address | null + input?: AddressFields + fetcherInput: AddressFields + body: { item: AddressFields } + actionInput: AddressFields +} + +export type UpdateItemHook = { + data: Address | null + input: { item?: AddressFields; wait?: number } + fetcherInput: { itemId: string; item: AddressFields } + body: { itemId: string; item: AddressFields } + actionInput: AddressFields & { id: string } +} + +export type RemoveItemHook = { + data: Address | null + input: { item?: Address } + fetcherInput: { itemId: string } + body: { itemId: string } + actionInput: { id: string } +} + +export type CustomerAddressHooks = { + getAddresses: GetAddressesHook + addItem: AddItemHook + updateItem: UpdateItemHook + removeItem: RemoveItemHook +} + +/** + * API endpoints for managing a customer's addresses. + */ + +export type AddItemHandler = AddItemHook & { + body: { cartId: string } +} + +export type UpdateItemHandler = UpdateItemHook & { + body: { cartId: string } +} + +export type RemoveItemHandler = RemoveItemHook & { + body: { cartId: string } +} + +export type CustomerAddressHandlers = { + getAddresses: GetAddressesHook + addItem: AddItemHandler + updateItem: UpdateItemHandler + removeItem: RemoveItemHandler +} + +export type CustomerAddressSchema = { + endpoint: { + options: {} + handlers: CustomerAddressHandlers + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/card.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/card.ts new file mode 100644 index 00000000000..37a134de834 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/card.ts @@ -0,0 +1,138 @@ +export interface Card { + /** + * Unique identifier for the card. + */ + id: string + /** + * Masked card number. Contains only the last 4 digits. + * @example "4242" + */ + mask: string + /** + * The card's brand. + * @example "Visa, Mastercard, etc." + */ + provider: string +} + +/** + * The fields required to create a new card. + */ +export interface CardFields { + /** + * Name on the card. + */ + cardHolder: string + /** + * The card's number, consisting of 16 digits. + */ + cardNumber: string + /** + * The card's expiry month and year, in the format MM/YY. + * @example "01/25" + */ + cardExpireDate: string + /** + * The card's security code, consisting of 3 digits. + */ + cardCvc: string + /** + * The customer's first name. + */ + firstName: string + /** + * The customer's last name. + */ + lastName: string + /** + * Company name. + */ + company: string + /** + * The customer's billing address street number. + */ + streetNumber: string + /** + * The customer's billing address zip code. + */ + zipCode: string + /** + * The customer's billing address city. + */ + city: string + /** + * The customer's billing address country. + */ + country: string +} + +/** + * Hooks for managing a customer's cards. + */ + +export type GetCardsHook = { + data: Card[] | null + input: {} + fetcherInput: { cartId?: string } + swrState: { isEmpty: boolean } +} + +export type AddItemHook = { + data: Card | null + input?: CardFields + fetcherInput: CardFields + body: { item: CardFields } + actionInput: CardFields +} + +export type UpdateItemHook = { + data: Card | null + input: { item?: CardFields; wait?: number } + fetcherInput: { itemId: string; item: CardFields } + body: { itemId: string; item: CardFields } + actionInput: CardFields & { id: string } +} + +export type RemoveItemHook = { + data: Card | null + input: { item?: Card } + fetcherInput: { itemId: string } + body: { itemId: string } + actionInput: { id: string } +} + +export interface CustomerCardHooks { + getCards: GetCardsHook + addItem: AddItemHook + updateItem: UpdateItemHook + removeItem: RemoveItemHook +} + +/** + * Customer card API handlers. + */ +export type AddItemHandler = AddItemHook & { + body: { cartId: string } +} + +export type UpdateItemHandler = UpdateItemHook & { + body: { cartId: string } +} + +export type RemoveItemHandler = RemoveItemHook & { + body: { cartId: string } +} + +export type CustomerCardHandlers = { + getCards: GetCardsHook + addItem: AddItemHandler + updateItem: UpdateItemHandler + removeItem: RemoveItemHandler +} + +export type CustomerCardSchema = { + endpoint: { + options: {} + handlers: CustomerCardHandlers + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/index.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/index.ts new file mode 100644 index 00000000000..89a963a2963 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/index.ts @@ -0,0 +1,54 @@ +export * as Card from './card' +export * as Address from './address' + +export interface Customer { + /** + * The unique identifier for the customer. + */ + id: string + /** + * The customer's first name. + */ + firstName: string + /** + * The customer's last name. + */ + lastName: string + /** + * The customer's email address. + */ + email?: string + /** + * The customer's phone number. + * @optional + */ + phone?: string + /** + * The customer's company name. + */ + company?: string + /** + * The customer's notes. + */ + notes?: string + /** + * Indicates wathever the customer accepts marketing, such as email newsletters. + */ + acceptsMarketing?: boolean +} + +export type CustomerHook = { + data: Customer | null | undefined + fetchData: { customer: Customer } | null +} + +export type CustomerSchema = { + endpoint: { + options: {} + handlers: { + getLoggedInCustomer: { + data: { customer: Customer } | null + } + } + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/default-fetcher.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/default-fetcher.ts new file mode 100644 index 00000000000..53312fc9663 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/default-fetcher.ts @@ -0,0 +1,12 @@ +import type { HookFetcherFn } from './types' + +export const SWRFetcher: HookFetcherFn = ({ options, fetch }) => + fetch(options) + +export const mutationFetcher: HookFetcherFn = ({ + input, + options, + fetch, +}) => fetch({ ...options, body: input }) + +export default SWRFetcher diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/define-property.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/define-property.ts new file mode 100644 index 00000000000..e8973522665 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/define-property.ts @@ -0,0 +1,37 @@ +// Taken from https://fettblog.eu/typescript-assertion-signatures/ + +type InferValue = Desc extends { + get(): any + value: any +} + ? never + : Desc extends { value: infer T } + ? Record + : Desc extends { get(): infer T } + ? Record + : never + +type DefineProperty< + Prop extends PropertyKey, + Desc extends PropertyDescriptor +> = Desc extends { writable: any; set(val: any): any } + ? never + : Desc extends { writable: any; get(): any } + ? never + : Desc extends { writable: false } + ? Readonly> + : Desc extends { writable: true } + ? InferValue + : Readonly> + +export default function defineProperty< + Obj extends object, + Key extends PropertyKey, + PDesc extends PropertyDescriptor +>( + obj: Obj, + prop: Key, + val: PDesc +): asserts obj is Obj & DefineProperty { + Object.defineProperty(obj, prop, val) +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts new file mode 100644 index 00000000000..d0045ca8812 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts @@ -0,0 +1,147 @@ +import type { SWRConfiguration } from 'swr' +import type { CommerceError } from '@plasmicpkgs/commerce' +import type { ResponseState } from './use-data' + +/** + * Returns the properties in T with the properties in type K, overriding properties defined in T + */ +export type Override = Omit & K + +/** + * Returns the properties in T with the properties in type K changed from optional to required + */ +export type PickRequired = Omit & { + [P in K]-?: NonNullable +} + +/** + * Core fetcher added by CommerceProvider + */ +export type Fetcher = ( + options: FetcherOptions +) => T | Promise + +export type FetcherOptions = { + url?: string + query?: string + method?: string + variables?: any + body?: Body +} + +export type HookFetcher = ( + options: HookFetcherOptions | null, + input: Input, + fetch: (options: FetcherOptions) => Promise +) => Data | Promise + +export type HookFetcherFn = ( + context: HookFetcherContext +) => H['data'] | Promise + +export type HookFetcherContext = { + options: HookFetcherOptions + input: H['fetcherInput'] + fetch: < + T = H['fetchData'] extends {} | null ? H['fetchData'] : any, + B = H['body'] + >( + options: FetcherOptions + ) => Promise +} + +export type HookFetcherOptions = { method?: string } & ( + | { query: string; url?: string } + | { query?: string; url: string } +) + +export type HookInputValue = string | number | boolean | null | undefined + +export type HookSWRInput = [string, HookInputValue][] + +export type HookFetchInput = { [k: string]: HookInputValue } + +export type HookFunction< + Input extends { [k: string]: unknown } | undefined, + T +> = keyof Input extends never + ? () => T + : Partial extends Input + ? (input?: Input) => T + : (input: Input) => T + +export type HookSchemaBase = { + // Data obj returned by the hook + data: any + // Input expected by the hook + input?: {} + // Input expected before doing a fetch operation (aka fetch handler) + fetcherInput?: {} + // Body object expected by the fetch operation + body?: {} + // Data returned by the fetch operation + fetchData?: any +} + +export type SWRHookSchemaBase = HookSchemaBase & { + // Custom state added to the response object of SWR + swrState?: {} + // Instances of MutationSchemaBase that the hook returns for better DX + mutations?: Record['useHook']>> +} + +export type MutationSchemaBase = HookSchemaBase & { + // Input expected by the action returned by the hook + actionInput?: {} +} + +/** + * Generates a SWR hook handler based on the schema of a hook + */ +export type SWRHook = { + useHook( + context: SWRHookContext + ): HookFunction< + H['input'] & { swrOptions?: SwrOptions }, + ResponseState & H['swrState'] & H['mutations'] + > + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn +} + +export type SWRHookContext = { + useData(context?: { + input?: HookFetchInput | HookSWRInput + swrOptions?: SwrOptions + }): ResponseState +} + +/** + * Generates a mutation hook handler based on the schema of a hook + */ +export type MutationHook = { + useHook( + context: MutationHookContext + ): HookFunction< + H['input'], + HookFunction> + > + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn +} + +export type MutationHookContext = { + fetch: keyof H['fetcherInput'] extends never + ? () => H['data'] | Promise + : Partial extends H['fetcherInput'] + ? (context?: { + input?: H['fetcherInput'] + }) => H['data'] | Promise + : (context: { input: H['fetcherInput'] }) => H['data'] | Promise +} + +export type SwrOptions = SWRConfiguration< + Data, + CommerceError, + HookFetcher +> diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx new file mode 100644 index 00000000000..55e839678c5 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx @@ -0,0 +1,78 @@ +import useSWR, { SWRResponse } from 'swr' +import type { + HookSWRInput, + HookFetchInput, + HookFetcherOptions, + HookFetcherFn, + Fetcher, + SwrOptions, + SWRHookSchemaBase, +} from './types' +import defineProperty from './define-property' +import { CommerceError } from '@plasmicpkgs/commerce' + +export type ResponseState = SWRResponse & { + isLoading: boolean +} + +export type UseData = ( + options: { + fetchOptions: HookFetcherOptions + fetcher: HookFetcherFn + }, + input: HookFetchInput | HookSWRInput, + fetcherFn: Fetcher, + swrOptions?: SwrOptions +) => ResponseState + +const useData: UseData = (options, input, fetcherFn, swrOptions) => { + const hookInput = Array.isArray(input) ? input : Object.entries(input) + const fetcher = async ( + url: string, + query?: string, + method?: string, + ...args: any[] + ) => { + try { + return await options.fetcher({ + options: { url, query, method }, + // Transform the input array into an object + input: args.reduce((obj, val, i) => { + obj[hookInput[i][0]!] = val + return obj + }, {}), + fetch: fetcherFn, + }) + } catch (error) { + // SWR will not log errors, but any error that's not an instance + // of CommerceError is not welcomed by this hook + if (!(error instanceof CommerceError)) { + console.error(error) + } + throw error + } + } + const response = useSWR( + () => { + const opts = options.fetchOptions + return opts + ? [opts.url, opts.query, opts.method, ...hookInput.map((e) => e[1])] + : null + }, + fetcher, + swrOptions + ) + + if (!('isLoading' in response)) { + defineProperty(response, 'isLoading', { + get() { + return response.data === undefined + }, + enumerable: true, + }) + } + + return response as typeof response & { isLoading: boolean } +} + +export default useData diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts new file mode 100644 index 00000000000..4403c066b6a --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts @@ -0,0 +1,50 @@ +import { useCallback } from 'react' +import { Provider, useCommerce } from '@plasmicpkgs/commerce' +import type { MutationHook, PickRequired, SWRHook } from './types' +import useData from './use-data' + +export function useFetcher() { + const { providerRef, fetcherRef } = useCommerce() + return providerRef.current.fetcher ?? fetcherRef.current +} + +export function useHook< + P extends Provider, + H extends MutationHook | SWRHook +>(fn: (provider: P) => H) { + const { providerRef } = useCommerce

() + const provider = providerRef.current + return fn(provider) +} + +export function useSWRHook>( + hook: PickRequired +) { + const fetcher = useFetcher() + + return hook.useHook({ + useData(ctx) { + const response = useData(hook, ctx?.input ?? [], fetcher, ctx?.swrOptions) + return response + }, + }) +} + +export function useMutationHook>( + hook: PickRequired +) { + const fetcher = useFetcher() + + return hook.useHook({ + fetch: useCallback( + ({ input } = {}) => { + return hook.fetcher({ + input, + options: hook.fetchOptions, + fetch: fetcher, + }) + }, + [fetcher, hook.fetchOptions] + ), + }) +} From 04179df648860aff6ea6a6612fecb5fbc7329091 Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 14:28:08 +0300 Subject: [PATCH 02/28] fix(spree): update checkout imports and provider types --- .../internal_pkgs/spree/src/checkout/use-checkout.tsx | 6 ++---- .../spree/src/commerce/checkout/use-checkout.ts | 3 ++- .../src/commerce/checkout/use-submit-checkout.tsx | 2 +- .../internal_pkgs/spree/src/commerce/index.tsx | 10 ++++++++++ .../internal_pkgs/spree/src/commerce/types/index.ts | 5 +++++ 5 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/commerce/types/index.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index bd8e3ac755e..64d355785c3 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -1,7 +1,5 @@ -import { SWRHook } from '@vercel/commerce/utils/types' -import useCheckout, { - UseCheckout, -} from '@vercel/commerce/checkout/use-checkout' +import { SWRHook } from '@plasmicpkgs/commerce' +import useCheckout, { UseCheckout } from '../commerce/checkout/use-checkout' export default useCheckout as UseCheckout diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts index 110add9b11a..634e266785e 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -4,7 +4,8 @@ import type { GetCheckoutHook } from '../types/checkout' import Cookies from 'js-cookie' import { useHook, useSWRHook } from '../utils/use-hook' -import { Provider, useCommerce } from '@plasmicpkgs/commerce' +import { useCommerce } from '@plasmicpkgs/commerce' +import { Provider } from '..' export type UseCheckout< H extends SWRHook = SWRHook diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx index b5219c22e7f..7304d0047a0 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx @@ -1,6 +1,6 @@ import type { HookFetcherFn, MutationHook } from '../utils/types' import type { SubmitCheckoutHook } from '../types/checkout' -import type { Provider } from '@plasmicpkgs/commerce' +import type { Provider } from '..' import { useHook, useMutationHook } from '../utils/use-hook' import { mutationFetcher } from '../utils/default-fetcher' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx new file mode 100644 index 00000000000..26e94ce49d3 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -0,0 +1,10 @@ +import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' +import type { SWRHook, MutationHook } from './utils/types' +import type { Checkout } from './types' + +export type Provider = BaseProvider & { + checkout?: { + useCheckout?: SWRHook + useSubmitCheckout?: MutationHook + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/index.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/index.ts new file mode 100644 index 00000000000..9b6b244126a --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/index.ts @@ -0,0 +1,5 @@ +import * as Checkout from './checkout' +import * as Common from './common' +import * as Customer from './customer' + +export type { Checkout, Common, Customer } From 8555aa547ba7b681372730c2708f020b0b0df2d3 Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 15:00:36 +0300 Subject: [PATCH 03/28] feat(spree): add checkout provider and update commerce integration --- .../spree/src/commerce/index.tsx | 20 ++++++++++++++++++- .../internal_pkgs/spree/src/provider.ts | 3 +++ .../internal_pkgs/spree/src/spree.tsx | 7 ++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx index 26e94ce49d3..6fffc7a0c12 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -1,6 +1,11 @@ -import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' +import { + CommerceProviderProps, + CoreCommerceProvider, + Provider as BaseProvider, +} from '@plasmicpkgs/commerce' import type { SWRHook, MutationHook } from './utils/types' import type { Checkout } from './types' +import React from 'react' export type Provider = BaseProvider & { checkout?: { @@ -8,3 +13,16 @@ export type Provider = BaseProvider & { useSubmitCheckout?: MutationHook } } + +export function getCommerceProvider

(provider: P) { + return function CommerceProvider({ + children, + ...props + }: CommerceProviderProps) { + return ( + + {children} + + ) + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts index de765f62eea..c4a3c12bedb 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts @@ -9,6 +9,7 @@ import { handler as useCategories } from './site/use-categories' import { handler as useBrands } from './site/use-brands' import { requireConfigValue } from './isomorphic-config' import type { Fetcher, FetcherOptions } from '@plasmicpkgs/commerce' +import useCheckout from './checkout/use-checkout' export const getSpreeProvider = (apiHost: string) => { return { @@ -19,6 +20,7 @@ export const getSpreeProvider = (apiHost: string) => { cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, products: { useSearch, useProduct }, site: { useCategories, useBrands }, + checkout: { useCheckout }, } } @@ -34,4 +36,5 @@ export type SpreeProvider = { } products: { useSearch: typeof useSearch; useProduct: typeof useProduct } site: { useCategories: typeof useCategories; useBrands: typeof useBrands } + checkout: { useCheckout: typeof useCheckout } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx index aba599f76b9..0d710203a13 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx @@ -1,8 +1,6 @@ -import { - getCommerceProvider as getCoreCommerceProvider, - useCommerce as useCoreCommerce, -} from '@plasmicpkgs/commerce' +import { useCommerce as useCoreCommerce } from '@plasmicpkgs/commerce' import { getSpreeProvider, SpreeProvider } from './provider' +import { getCommerceProvider as getCoreCommerceProvider } from './commerce' export type { SpreeProvider } @@ -10,4 +8,3 @@ export const useCommerce = () => useCoreCommerce() export const getCommerceProvider = (apiHost: string) => getCoreCommerceProvider(getSpreeProvider(apiHost)) - From 1776e2a75c4855d7e2c13a61944d000315a5c7d7 Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 15:12:47 +0300 Subject: [PATCH 04/28] feat(spree): add checkout component registration --- .../internal_pkgs/spree/src/index.tsx | 14 ++++---- .../spree/src/registerCheckout.tsx | 34 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx diff --git a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx index 826d04b865d..283eafcd98d 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx @@ -1,14 +1,16 @@ -import { Registerable } from "./registerable"; +import { Registerable } from './registerable' import { registerCommerceProvider, CommerceProviderComponent, -} from "./registerCommerceProvider"; -export * from "./registerable"; +} from './registerCommerceProvider' +import { registerCheckout } from './registerCheckout' +export * from './registerable' -export * from "./spree"; +export * from './spree' export function registerAll(loader?: Registerable) { - registerCommerceProvider(loader); + registerCommerceProvider(loader) + registerCheckout(loader) } -export { registerCommerceProvider, CommerceProviderComponent }; +export { registerCommerceProvider, CommerceProviderComponent } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx new file mode 100644 index 00000000000..1aacc74806b --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx @@ -0,0 +1,34 @@ +import registerComponent, { + ComponentMeta, +} from '@plasmicapp/host/registerComponent' +import { Registerable } from './registerable' +import React from 'react' + +interface CheckoutProps { + className?: string +} + +export const cartMeta: ComponentMeta = { + name: 'plasmic-commerce-cart', + displayName: 'Checkout', + description: + 'Shows the checkout order page with the cart items and total price.', + props: {}, + importPath: '@plasmicpkgs/commerce', + importName: 'CheckoutComponent', +} + +export function CheckoutComponent(props: CheckoutProps) { + const { className } = props + + return Checkout Order +} + +export function registerCheckout( + loader?: Registerable, + customCartMeta?: ComponentMeta +) { + const doRegisterComponent: typeof registerComponent = (...args) => + loader ? loader.registerComponent(...args) : registerComponent(...args) + doRegisterComponent(CheckoutComponent, customCartMeta ?? cartMeta) +} From b4742e89973ad80139c3d8a3320a602ce656b3fc Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 15:55:10 +0300 Subject: [PATCH 05/28] fix(spree): update checkout component registration and exports --- .../canvas-packages/internal_pkgs/spree/src/index.tsx | 1 + .../internal_pkgs/spree/src/registerCheckout.tsx | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx index 283eafcd98d..37583dd887f 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx @@ -5,6 +5,7 @@ import { } from './registerCommerceProvider' import { registerCheckout } from './registerCheckout' export * from './registerable' +export * from './registerCheckout' export * from './spree' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx index 1aacc74806b..4ec83e43d02 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx @@ -8,13 +8,13 @@ interface CheckoutProps { className?: string } -export const cartMeta: ComponentMeta = { - name: 'plasmic-commerce-cart', +export const checkoutMeta: ComponentMeta = { + name: 'plasmic-commerce-checkout', displayName: 'Checkout', description: 'Shows the checkout order page with the cart items and total price.', props: {}, - importPath: '@plasmicpkgs/commerce', + importPath: 'commerce-spree', importName: 'CheckoutComponent', } @@ -26,9 +26,9 @@ export function CheckoutComponent(props: CheckoutProps) { export function registerCheckout( loader?: Registerable, - customCartMeta?: ComponentMeta + customCheckoutMeta?: ComponentMeta ) { const doRegisterComponent: typeof registerComponent = (...args) => loader ? loader.registerComponent(...args) : registerComponent(...args) - doRegisterComponent(CheckoutComponent, customCartMeta ?? cartMeta) + doRegisterComponent(CheckoutComponent, customCheckoutMeta ?? checkoutMeta) } From 679056acbecffc5054447ebceff03b34751f8180 Mon Sep 17 00:00:00 2001 From: willymwai Date: Tue, 14 Jan 2025 16:34:12 +0300 Subject: [PATCH 06/28] fix(spree): update checkout component name and add type imports --- .../internal_pkgs/spree/src/checkout/use-checkout.tsx | 3 ++- .../internal_pkgs/spree/src/registerCheckout.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 64d355785c3..8178c98ceb5 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -1,9 +1,10 @@ import { SWRHook } from '@plasmicpkgs/commerce' import useCheckout, { UseCheckout } from '../commerce/checkout/use-checkout' +import type { GetCheckoutHook } from '../commerce/types/checkout' export default useCheckout as UseCheckout -export const handler: SWRHook = { +export const handler: SWRHook = { // Provide fetchOptions for SWR cache key fetchOptions: { // TODO: Revise url and query diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx index 4ec83e43d02..517b2c49642 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx @@ -9,7 +9,7 @@ interface CheckoutProps { } export const checkoutMeta: ComponentMeta = { - name: 'plasmic-commerce-checkout', + name: 'commerce-spree-checkout', displayName: 'Checkout', description: 'Shows the checkout order page with the cart items and total price.', From 8f779af9ed56dfba938743f8b101c8a36059a6df Mon Sep 17 00:00:00 2001 From: willymwai Date: Wed, 15 Jan 2025 10:22:46 +0300 Subject: [PATCH 07/28] feat(spree): update commerce provider context and checkout types --- .../spree/src/checkout/use-checkout.tsx | 3 +- .../spree/src/commerce/index.tsx | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 8178c98ceb5..64d355785c3 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -1,10 +1,9 @@ import { SWRHook } from '@plasmicpkgs/commerce' import useCheckout, { UseCheckout } from '../commerce/checkout/use-checkout' -import type { GetCheckoutHook } from '../commerce/types/checkout' export default useCheckout as UseCheckout -export const handler: SWRHook = { +export const handler: SWRHook = { // Provide fetchOptions for SWR cache key fetchOptions: { // TODO: Revise url and query diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx index 6fffc7a0c12..603e013a5ab 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -1,19 +1,46 @@ -import { +import type { + CommerceConfig, + CommerceProps, CommerceProviderProps, - CoreCommerceProvider, Provider as BaseProvider, + Fetcher, } from '@plasmicpkgs/commerce' import type { SWRHook, MutationHook } from './utils/types' import type { Checkout } from './types' -import React from 'react' +import React, { createContext, MutableRefObject, useMemo, useRef } from 'react' + +export type CommerceContextValue

= { + providerRef: MutableRefObject

+ fetcherRef: MutableRefObject +} & CommerceConfig + +const Commerce = createContext | {}>({}) export type Provider = BaseProvider & { checkout?: { - useCheckout?: SWRHook + useCheckout?: SWRHook | any useSubmitCheckout?: MutationHook } } +export function CoreCommerceProvider

({ + provider, + children, +}: CommerceProps

) { + const providerRef = useRef(provider) + // TODO: Remove the fetcherRef + const fetcherRef = useRef(provider.fetcher) + // If the parent re-renders this provider will re-render every + // consumer unless we memoize the config + const { locale, cartCookie } = providerRef.current + const cfg = useMemo( + () => ({ providerRef, fetcherRef, locale, cartCookie }), + [locale, cartCookie] + ) + + return {children} +} + export function getCommerceProvider

(provider: P) { return function CommerceProvider({ children, From 8d0ef9fd3feb9fc1e0c1e7ebd937fca564ea5e4c Mon Sep 17 00:00:00 2001 From: willymwai Date: Wed, 15 Jan 2025 14:19:51 +0300 Subject: [PATCH 08/28] chore: bump commerce-spree package version to 0.0.31 and update checkout integration --- .../internal_pkgs/spree/package.json | 2 +- .../spree/src/commerce/index.tsx | 52 ++++++++++++++----- .../internal_pkgs/spree/src/index.tsx | 8 +-- .../internal_pkgs/spree/src/provider.ts | 6 +-- .../spree/src/registerCheckout.tsx | 2 +- .../internal_pkgs/spree/src/spree.tsx | 2 +- platform/canvas-packages/package.json | 2 +- platform/canvas-packages/yarn.lock | 8 +-- platform/loader-bundle-env/package.json | 2 +- platform/loader-bundle-env/yarn.lock | 8 +-- 10 files changed, 56 insertions(+), 36 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/package.json b/platform/canvas-packages/internal_pkgs/spree/package.json index f2e1d2c7d33..ba596517063 100644 --- a/platform/canvas-packages/internal_pkgs/spree/package.json +++ b/platform/canvas-packages/internal_pkgs/spree/package.json @@ -1,6 +1,6 @@ { "name": "commerce-spree", - "version": "0.0.30", + "version": "0.0.31", "description": "Plasmic registration calls for spree commerce provider", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx index 603e013a5ab..f94154d24ba 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -1,18 +1,15 @@ -import type { - CommerceConfig, - CommerceProps, - CommerceProviderProps, - Provider as BaseProvider, - Fetcher, -} from '@plasmicpkgs/commerce' -import type { SWRHook, MutationHook } from './utils/types' -import type { Checkout } from './types' -import React, { createContext, MutableRefObject, useMemo, useRef } from 'react' +import React, { + ReactNode, + MutableRefObject, + createContext, + useContext, + useMemo, + useRef, +} from 'react' +import type { Fetcher, SWRHook, MutationHook } from './utils/types' -export type CommerceContextValue

= { - providerRef: MutableRefObject

- fetcherRef: MutableRefObject -} & CommerceConfig +import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' +import { Checkout } from './types' const Commerce = createContext | {}>({}) @@ -23,6 +20,29 @@ export type Provider = BaseProvider & { } } +export type CommerceConfig = { + locale: string + cartCookie: string +} + +export type CommerceContextValue

= { + providerRef: MutableRefObject

+ fetcherRef: MutableRefObject +} & CommerceConfig + +export type CommerceProps

= { + children?: ReactNode + provider: P +} + +/** + * These are the properties every provider should allow when implementing + * the core commerce provider + */ +export type CommerceProviderProps = { + children?: ReactNode +} & Partial + export function CoreCommerceProvider

({ provider, children, @@ -53,3 +73,7 @@ export function getCommerceProvider

(provider: P) { ) } } + +export function useCommerce

() { + return useContext(Commerce) as CommerceContextValue

+} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx index 37583dd887f..07a3003f48f 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx @@ -1,11 +1,9 @@ import { Registerable } from './registerable' -import { - registerCommerceProvider, - CommerceProviderComponent, -} from './registerCommerceProvider' +import { registerCommerceProvider } from './registerCommerceProvider' import { registerCheckout } from './registerCheckout' export * from './registerable' export * from './registerCheckout' +export * from './registerCommerceProvider' export * from './spree' @@ -13,5 +11,3 @@ export function registerAll(loader?: Registerable) { registerCommerceProvider(loader) registerCheckout(loader) } - -export { registerCommerceProvider, CommerceProviderComponent } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts index c4a3c12bedb..c24b4a264d1 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts @@ -9,7 +9,7 @@ import { handler as useCategories } from './site/use-categories' import { handler as useBrands } from './site/use-brands' import { requireConfigValue } from './isomorphic-config' import type { Fetcher, FetcherOptions } from '@plasmicpkgs/commerce' -import useCheckout from './checkout/use-checkout' +// import useCheckout from './checkout/use-checkout' export const getSpreeProvider = (apiHost: string) => { return { @@ -20,7 +20,7 @@ export const getSpreeProvider = (apiHost: string) => { cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, products: { useSearch, useProduct }, site: { useCategories, useBrands }, - checkout: { useCheckout }, + // checkout: { useCheckout }, } } @@ -36,5 +36,5 @@ export type SpreeProvider = { } products: { useSearch: typeof useSearch; useProduct: typeof useProduct } site: { useCategories: typeof useCategories; useBrands: typeof useBrands } - checkout: { useCheckout: typeof useCheckout } + // checkout: { useCheckout: typeof useCheckout } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx index 517b2c49642..39512ab8601 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx @@ -9,7 +9,7 @@ interface CheckoutProps { } export const checkoutMeta: ComponentMeta = { - name: 'commerce-spree-checkout', + name: 'plasmic-commerce-spree-checkout', displayName: 'Checkout', description: 'Shows the checkout order page with the cart items and total price.', diff --git a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx index 0d710203a13..35a01f18a3a 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx @@ -1,6 +1,6 @@ import { useCommerce as useCoreCommerce } from '@plasmicpkgs/commerce' import { getSpreeProvider, SpreeProvider } from './provider' -import { getCommerceProvider as getCoreCommerceProvider } from './commerce' +import { getCommerceProvider as getCoreCommerceProvider } from '@plasmicpkgs/commerce' export type { SpreeProvider } diff --git a/platform/canvas-packages/package.json b/platform/canvas-packages/package.json index 511fc6c0b89..6666dd769ce 100644 --- a/platform/canvas-packages/package.json +++ b/platform/canvas-packages/package.json @@ -70,7 +70,7 @@ "axios": "^1.5.1", "chart.js": "^4.2.1", "classnames": "^2.3.2", - "commerce-spree": "^0.0.30", + "commerce-spree": "^0.0.31", "copy-to-clipboard": "^3.3.3", "date-fns": "^2.30.0", "dayjs": "^1.11.10", diff --git a/platform/canvas-packages/yarn.lock b/platform/canvas-packages/yarn.lock index 2d588912cb5..c658e8482ea 100644 --- a/platform/canvas-packages/yarn.lock +++ b/platform/canvas-packages/yarn.lock @@ -7284,10 +7284,10 @@ commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commerce-spree@^0.0.30: - version "0.0.30" - resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.30.tgz#d44248f6a109cd1bd9a7403bdd06704a1f0c2a98" - integrity sha512-NQHylP/9pwNMkl0HYfYXNNh6G7b0QXB9wwQHWrYRrgDouAF1sP3vcIAKthOba1EwCAkZnhPc/CKBstQAC0sDfw== +commerce-spree@^0.0.31: + version "0.0.31" + resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.31.tgz#8b70d455021f3fee89ab0a4bb435fb4b64e63a2d" + integrity sha512-WM8v32Q8Q0FVPY6OwHG30yFhsH0hHoSAPtvKwYEAt5lXRW1T8bqO0Vq3JguGBmaw8C3OGFfEU/dab22mtxdjig== dependencies: "@plasmicpkgs/commerce" "0.0.205" "@spree/storefront-api-v2-sdk" "^5.1.1" diff --git a/platform/loader-bundle-env/package.json b/platform/loader-bundle-env/package.json index 8a86bde883a..905b8c2cd37 100644 --- a/platform/loader-bundle-env/package.json +++ b/platform/loader-bundle-env/package.json @@ -26,7 +26,7 @@ "@plasmicpkgs/commerce-saleor": "^0.0.170", "@plasmicpkgs/commerce-shopify": "^0.0.213", "@plasmicpkgs/commerce-swell": "^0.0.215", - "commerce-spree": "^0.0.30", + "commerce-spree": "^0.0.31", "@plasmicpkgs/framer-motion": "^0.0.206", "@plasmicpkgs/lottie-react": "^0.0.199", "@plasmicpkgs/plasmic-basic-components": "^0.0.231", diff --git a/platform/loader-bundle-env/yarn.lock b/platform/loader-bundle-env/yarn.lock index 641486ce58e..e6a5be5c110 100644 --- a/platform/loader-bundle-env/yarn.lock +++ b/platform/loader-bundle-env/yarn.lock @@ -6664,10 +6664,10 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commerce-spree@^0.0.30: - version "0.0.30" - resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.30.tgz#d44248f6a109cd1bd9a7403bdd06704a1f0c2a98" - integrity sha512-NQHylP/9pwNMkl0HYfYXNNh6G7b0QXB9wwQHWrYRrgDouAF1sP3vcIAKthOba1EwCAkZnhPc/CKBstQAC0sDfw== +commerce-spree@^0.0.31: + version "0.0.31" + resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.31.tgz#8b70d455021f3fee89ab0a4bb435fb4b64e63a2d" + integrity sha512-WM8v32Q8Q0FVPY6OwHG30yFhsH0hHoSAPtvKwYEAt5lXRW1T8bqO0Vq3JguGBmaw8C3OGFfEU/dab22mtxdjig== dependencies: "@plasmicpkgs/commerce" "0.0.205" "@spree/storefront-api-v2-sdk" "^5.1.1" From d612fea3ed9a7743df46417cd64e435cd72e284d Mon Sep 17 00:00:00 2001 From: willymwai Date: Wed, 15 Jan 2025 16:36:32 +0300 Subject: [PATCH 09/28] feat(spree): add checkout types and update provider integration --- .../src/commerce/checkout/use-checkout.ts | 2 +- .../spree/src/commerce/index.tsx | 2 +- .../internal_pkgs/spree/src/provider.ts | 10 +- .../spree/src/registerCheckout.tsx | 21 +-- .../spree/src/types/provider.d.ts | 12 ++ .../internal_pkgs/spree/src/utils/types.ts | 153 ++++++++++++++++++ 6 files changed, 185 insertions(+), 15 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts index 634e266785e..81ae4c2a565 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -4,7 +4,7 @@ import type { GetCheckoutHook } from '../types/checkout' import Cookies from 'js-cookie' import { useHook, useSWRHook } from '../utils/use-hook' -import { useCommerce } from '@plasmicpkgs/commerce' +import { useCommerce } from '..' import { Provider } from '..' export type UseCheckout< diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx index f94154d24ba..1f35d8dccfc 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -16,7 +16,7 @@ const Commerce = createContext | {}>({}) export type Provider = BaseProvider & { checkout?: { useCheckout?: SWRHook | any - useSubmitCheckout?: MutationHook + useSubmitCheckout?: MutationHook | any } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts index c24b4a264d1..6478afa65ce 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts @@ -9,7 +9,8 @@ import { handler as useCategories } from './site/use-categories' import { handler as useBrands } from './site/use-brands' import { requireConfigValue } from './isomorphic-config' import type { Fetcher, FetcherOptions } from '@plasmicpkgs/commerce' -// import useCheckout from './checkout/use-checkout' +import useCheckout from './checkout/use-checkout' +import useSubmitCheckout from './commerce/checkout/use-submit-checkout' export const getSpreeProvider = (apiHost: string) => { return { @@ -20,7 +21,7 @@ export const getSpreeProvider = (apiHost: string) => { cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, products: { useSearch, useProduct }, site: { useCategories, useBrands }, - // checkout: { useCheckout }, + checkout: { useCheckout, useSubmitCheckout }, } } @@ -36,5 +37,8 @@ export type SpreeProvider = { } products: { useSearch: typeof useSearch; useProduct: typeof useProduct } site: { useCategories: typeof useCategories; useBrands: typeof useBrands } - // checkout: { useCheckout: typeof useCheckout } + checkout: { + useCheckout: typeof useCheckout + useSubmitCheckout: typeof useSubmitCheckout + } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx index 39512ab8601..d4b26bbeb43 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx @@ -3,12 +3,10 @@ import registerComponent, { } from '@plasmicapp/host/registerComponent' import { Registerable } from './registerable' import React from 'react' +import useCheckout from './checkout/use-checkout' +import { DataProvider } from '@plasmicapp/host' -interface CheckoutProps { - className?: string -} - -export const checkoutMeta: ComponentMeta = { +export const checkoutMeta: ComponentMeta> = { name: 'plasmic-commerce-spree-checkout', displayName: 'Checkout', description: @@ -18,15 +16,18 @@ export const checkoutMeta: ComponentMeta = { importName: 'CheckoutComponent', } -export function CheckoutComponent(props: CheckoutProps) { - const { className } = props - - return Checkout Order +export function CheckoutComponent(props: React.PropsWithChildren) { + const { data } = useCheckout() + return ( + + {props.children} + + ) } export function registerCheckout( loader?: Registerable, - customCheckoutMeta?: ComponentMeta + customCheckoutMeta?: ComponentMeta> ) { const doRegisterComponent: typeof registerComponent = (...args) => loader ? loader.registerComponent(...args) : registerComponent(...args) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts b/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts new file mode 100644 index 00000000000..d0166193124 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts @@ -0,0 +1,12 @@ +import type { MutationHook, SWRHook } from '../commerce/utils/types' +import { Checkout } from '../commerce/types' +import type { Provider as OriginalProvider } from '@plasmicpkgs/commerce' + +declare module '@plasmicpkgs/commerce' { + export interface Provider extends OriginalProvider { + checkout?: { + useCheckout?: SWRHook | any + useSubmitCheckout?: MutationHook | any + } + } +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts new file mode 100644 index 00000000000..480db2525fd --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts @@ -0,0 +1,153 @@ +import type { SWRConfiguration } from 'swr' +import type { CommerceError } from '@plasmicpkgs/commerce' +import type { ResponseState } from '../commerce/utils/use-data' +import { Provider } from '../commerce' + +/** + * Returns the properties in T with the properties in type K, overriding properties defined in T + */ +export type Override = Omit & K + +/** + * Returns the properties in T with the properties in type K changed from optional to required + */ +export type PickRequired = Omit & { + [P in K]-?: NonNullable +} + +/** + * Core fetcher added by CommerceProvider + */ +export type Fetcher = ( + options: FetcherOptions +) => T | Promise + +export type FetcherOptions = { + url?: string + query?: string + method?: string + variables?: any + body?: Body +} + +export type HookFetcher = ( + options: HookFetcherOptions | null, + input: Input, + fetch: (options: FetcherOptions) => Promise +) => Data | Promise + +export type HookFetcherFn = ( + context: HookFetcherContext +) => H['data'] | Promise + +export type HookFetcherContext = { + options: HookFetcherOptions + input: H['fetcherInput'] + fetch: < + T = H['fetchData'] extends {} | null ? H['fetchData'] : any, + B = H['body'] + >( + options: FetcherOptions + ) => Promise + provider?: Provider +} + +export type HookFetcherOptions = { method?: string } & ( + | { query: string; url?: string } + | { query?: string; url: string } +) + +export type HookInputValue = string | number | boolean | undefined + +export type HookSWRInput = [string, HookInputValue][] + +export type HookFetchInput = { [k: string]: HookInputValue } + +export type HookFunction< + Input extends { [k: string]: unknown } | undefined, + T +> = keyof Input extends never + ? () => T + : Partial extends Input + ? (input?: Input) => T + : (input: Input) => T + +export type HookSchemaBase = { + // Data obj returned by the hook + data: any + // Input expected by the hook + input?: {} + // Input expected before doing a fetch operation (aka fetch handler) + fetcherInput?: {} + // Body object expected by the fetch operation + body?: {} + // Data returned by the fetch operation + fetchData?: any +} + +export type SWRHookSchemaBase = HookSchemaBase & { + // Custom state added to the response object of SWR + swrState?: {} + // Instances of MutationSchemaBase that the hook returns for better DX + mutations?: Record['useHook']>> +} + +export type MutationSchemaBase = HookSchemaBase & { + // Input expected by the action returned by the hook + actionInput?: {} +} + +/** + * Generates a SWR hook handler based on the schema of a hook + */ +export type SWRHook = { + useHook( + context: SWRHookContext + ): HookFunction< + H['input'] & { swrOptions?: SwrOptions }, + ResponseState & H['swrState'] & H['mutations'] + > + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn +} + +export type SWRHookContext = { + useData(context?: { + input?: HookFetchInput | HookSWRInput + swrOptions?: SwrOptions + }): ResponseState +} + +/** + * Generates a mutation hook handler based on the schema of a hook + */ +export type MutationHook = { + useHook( + context: MutationHookContext + ): HookFunction< + H['input'], + HookFunction> + > + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn +} + +export type MutationHookContext = { + fetch: keyof H['fetcherInput'] extends never + ? () => H['data'] | Promise + : Partial extends H['fetcherInput'] + ? (context?: { + input?: H['fetcherInput'] + }) => H['data'] | Promise + : (context: { input: H['fetcherInput'] }) => H['data'] | Promise +} + +export type SwrOptions = SWRConfiguration< + Data, + CommerceError, + HookFetcher +> + +export type CommerceExtraFeatures = { + includeSubCategories?: boolean +} From 0d7e696f1ab450417e78a5215f5bd9a5c5dc4834 Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 09:57:04 +0300 Subject: [PATCH 10/28] fix(spree): update commerce imports and provider types --- .../spree/src/commerce/checkout/use-checkout.ts | 4 ++-- .../commerce/checkout/use-submit-checkout.tsx | 2 +- .../internal_pkgs/spree/src/commerce/index.tsx | 17 ++++++----------- .../spree/src/commerce/utils/use-hook.ts | 3 ++- .../internal_pkgs/spree/src/spree.tsx | 4 ++-- .../internal_pkgs/spree/src/types/provider.d.ts | 4 ++-- .../internal_pkgs/spree/src/utils/types.ts | 2 +- 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts index 81ae4c2a565..4ee293b7262 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -4,8 +4,8 @@ import type { GetCheckoutHook } from '../types/checkout' import Cookies from 'js-cookie' import { useHook, useSWRHook } from '../utils/use-hook' -import { useCommerce } from '..' -import { Provider } from '..' +import { useCommerce } from '@plasmicpkgs/commerce' +import { Provider } from '@plasmicpkgs/commerce' export type UseCheckout< H extends SWRHook = SWRHook diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx index 7304d0047a0..b5219c22e7f 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx @@ -1,6 +1,6 @@ import type { HookFetcherFn, MutationHook } from '../utils/types' import type { SubmitCheckoutHook } from '../types/checkout' -import type { Provider } from '..' +import type { Provider } from '@plasmicpkgs/commerce' import { useHook, useMutationHook } from '../utils/use-hook' import { mutationFetcher } from '../utils/default-fetcher' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx index 1f35d8dccfc..e02242360cb 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/index.tsx @@ -1,3 +1,7 @@ +/* + Forked from https://github.com/vercel/commerce/tree/main/packages/commerce/src + Changes: Removed authentication, customer and wishlist hooks +*/ import React, { ReactNode, MutableRefObject, @@ -6,20 +10,11 @@ import React, { useMemo, useRef, } from 'react' -import type { Fetcher, SWRHook, MutationHook } from './utils/types' - -import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' -import { Checkout } from './types' +import type { Fetcher } from './utils/types' +import { Provider } from '@plasmicpkgs/commerce' const Commerce = createContext | {}>({}) -export type Provider = BaseProvider & { - checkout?: { - useCheckout?: SWRHook | any - useSubmitCheckout?: MutationHook | any - } -} - export type CommerceConfig = { locale: string cartCookie: string diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts index 4403c066b6a..3534f34ffab 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts @@ -1,5 +1,6 @@ import { useCallback } from 'react' -import { Provider, useCommerce } from '@plasmicpkgs/commerce' +import { Provider } from '@plasmicpkgs/commerce' +import { useCommerce } from '..' import type { MutationHook, PickRequired, SWRHook } from './types' import useData from './use-data' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx index 35a01f18a3a..573fe333834 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx @@ -1,6 +1,6 @@ -import { useCommerce as useCoreCommerce } from '@plasmicpkgs/commerce' +import { useCommerce as useCoreCommerce } from './commerce' import { getSpreeProvider, SpreeProvider } from './provider' -import { getCommerceProvider as getCoreCommerceProvider } from '@plasmicpkgs/commerce' +import { getCommerceProvider as getCoreCommerceProvider } from './commerce' export type { SpreeProvider } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts b/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts index d0166193124..0f0ce7ecc28 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts @@ -1,9 +1,9 @@ import type { MutationHook, SWRHook } from '../commerce/utils/types' import { Checkout } from '../commerce/types' -import type { Provider as OriginalProvider } from '@plasmicpkgs/commerce' +import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' declare module '@plasmicpkgs/commerce' { - export interface Provider extends OriginalProvider { + type Provider = BaseProvider & { checkout?: { useCheckout?: SWRHook | any useSubmitCheckout?: MutationHook | any diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts index 480db2525fd..7b841dee3ef 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/types.ts @@ -1,7 +1,7 @@ import type { SWRConfiguration } from 'swr' import type { CommerceError } from '@plasmicpkgs/commerce' import type { ResponseState } from '../commerce/utils/use-data' -import { Provider } from '../commerce' +import { Provider } from '@plasmicpkgs/commerce' /** * Returns the properties in T with the properties in type K, overriding properties defined in T From 3e00c6d8908f24973ed0feeb77049937dcbc6b94 Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 10:35:07 +0300 Subject: [PATCH 11/28] fix(spree): update imports and add patch-package dependency --- .../internal_pkgs/spree/package.json | 1 + .../@plasmicpkgs+commerce+0.0.205.patch | 40 +++++ .../src/commerce/checkout/use-checkout.ts | 6 +- .../internal_pkgs/spree/src/spree.tsx | 2 +- .../internal_pkgs/spree/yarn.lock | 140 +++++++++++++++++- 5 files changed, 182 insertions(+), 7 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/patches/@plasmicpkgs+commerce+0.0.205.patch diff --git a/platform/canvas-packages/internal_pkgs/spree/package.json b/platform/canvas-packages/internal_pkgs/spree/package.json index ba596517063..68e4878d670 100644 --- a/platform/canvas-packages/internal_pkgs/spree/package.json +++ b/platform/canvas-packages/internal_pkgs/spree/package.json @@ -38,6 +38,7 @@ "@types/node": "^17.0.8", "@types/react": "^18.0.27", "next": "^12.0.8", + "patch-package": "^8.0.0", "prettier": "^2.5.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/platform/canvas-packages/internal_pkgs/spree/patches/@plasmicpkgs+commerce+0.0.205.patch b/platform/canvas-packages/internal_pkgs/spree/patches/@plasmicpkgs+commerce+0.0.205.patch new file mode 100644 index 00000000000..f71576efbc6 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/patches/@plasmicpkgs+commerce+0.0.205.patch @@ -0,0 +1,40 @@ +diff --git a/node_modules/@plasmicpkgs/commerce/dist/commerce.d.ts b/node_modules/@plasmicpkgs/commerce/dist/commerce.d.ts +index a23a631..e4075b1 100644 +--- a/node_modules/@plasmicpkgs/commerce/dist/commerce.d.ts ++++ b/node_modules/@plasmicpkgs/commerce/dist/commerce.d.ts +@@ -18,6 +18,35 @@ export declare type Provider = CommerceConfig & { + useBrands?: SWRHook; + }; + extraFeatures?: CommerceExtraFeatures; ++ checkout?: { ++ useCheckout?: SWRHook ++ useSubmitCheckout?: MutationHook ++ } ++ wishlist?: { ++ useWishlist?: SWRHook ++ useAddItem?: MutationHook ++ useRemoveItem?: MutationHook ++ } ++ customer?: { ++ useCustomer?: SWRHook ++ card?: { ++ useCards?: SWRHook ++ useAddItem?: MutationHook ++ useUpdateItem?: MutationHook ++ useRemoveItem?: MutationHook ++ } ++ address?: { ++ useAddresses?: SWRHook ++ useAddItem?: MutationHook ++ useUpdateItem?: MutationHook ++ useRemoveItem?: MutationHook ++ } ++ } ++ auth?: { ++ useSignup?: MutationHook ++ useLogin?: MutationHook ++ useLogout?: MutationHook ++ } + }; + export declare type CommerceConfig = { + locale: string; diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts index 4ee293b7262..83428c38f3e 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -4,7 +4,7 @@ import type { GetCheckoutHook } from '../types/checkout' import Cookies from 'js-cookie' import { useHook, useSWRHook } from '../utils/use-hook' -import { useCommerce } from '@plasmicpkgs/commerce' +import { useCommerce } from '..' import { Provider } from '@plasmicpkgs/commerce' export type UseCheckout< @@ -19,7 +19,9 @@ export const fetcher: HookFetcherFn = async ({ return cartId ? await fetch(options) : null } -const fn = (provider: Provider) => provider.checkout?.useCheckout! +const fn = (provider: Provider) => { + return provider.checkout?.useCheckout! +} const useCheckout: UseCheckout = (input) => { const hook = useHook(fn) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx index 573fe333834..0d710203a13 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx @@ -1,4 +1,4 @@ -import { useCommerce as useCoreCommerce } from './commerce' +import { useCommerce as useCoreCommerce } from '@plasmicpkgs/commerce' import { getSpreeProvider, SpreeProvider } from './provider' import { getCommerceProvider as getCoreCommerceProvider } from './commerce' diff --git a/platform/canvas-packages/internal_pkgs/spree/yarn.lock b/platform/canvas-packages/internal_pkgs/spree/yarn.lock index 4dc3b63fc5e..76fbcad09d5 100644 --- a/platform/canvas-packages/internal_pkgs/spree/yarn.lock +++ b/platform/canvas-packages/internal_pkgs/spree/yarn.lock @@ -1612,6 +1612,11 @@ agentkeepalive "^4.2.1" debug "^4.3.3" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + "@zeit/dns-cached-resolve@^2.1.2": version "2.1.2" resolved "https://registry.npmjs.org/@zeit/dns-cached-resolve/-/dns-cached-resolve-2.1.2.tgz" @@ -2207,7 +2212,7 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -call-bind-apply-helpers@^1.0.0: +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz" integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== @@ -2225,6 +2230,14 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7, call-bin get-intrinsic "^1.2.4" set-function-length "^1.2.2" +call-bound@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" @@ -2274,7 +2287,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2307,6 +2320,11 @@ ci-info@^2.0.0: resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + ci-job-number@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/ci-job-number/-/ci-job-number-1.2.2.tgz" @@ -2488,7 +2506,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -2712,6 +2730,15 @@ dunder-proto@^1.0.0: es-errors "^1.3.0" gopd "^1.2.0" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" @@ -3498,6 +3525,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz" @@ -3632,11 +3666,35 @@ get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: has-symbols "^1.1.0" hasown "^2.0.2" +get-intrinsic@^1.2.6: + version "1.2.7" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.7.tgz#dcfcb33d3272e15f445d15124bc0a216189b9044" + integrity sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + get-proto "^1.0.0" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-proto@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz" @@ -3743,7 +3801,7 @@ gopd@^1.0.1, gopd@^1.1.0, gopd@^1.2.0: resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4857,6 +4915,17 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json-stable-stringify@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.2.1.tgz#addb683c2b78014d0b78d704c2fcbdf0695a60e2" + integrity sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" @@ -4890,6 +4959,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + jsprim@^1.2.2: version "1.4.2" resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" @@ -4929,6 +5003,13 @@ kind-of@^6.0.2: resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -5097,6 +5178,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" @@ -5454,6 +5540,14 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +open@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" @@ -5554,6 +5648,27 @@ pascalcase@^0.1.1: resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + ci-info "^3.7.0" + cross-spawn "^7.0.3" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" @@ -6056,6 +6171,13 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" +rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -6343,6 +6465,11 @@ size-limit@^7.0.8: nanospinner "^1.0.0" picocolors "^1.0.0" +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -7384,6 +7511,11 @@ yaml@^1.7.2: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.2.2: + version "2.7.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.7.0.tgz#aef9bb617a64c937a9a748803786ad8d3ffe1e98" + integrity sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA== + yargs-parser@18.x, yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" From 19945aa5366742549ea020383bd452d592c9a2ce Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 11:15:03 +0300 Subject: [PATCH 12/28] fix(spree): simplify checkout integration and update imports --- .../spree/src/commerce/checkout/use-checkout.ts | 7 ++----- .../spree/src/commerce/utils/use-hook.ts | 3 +-- .../internal_pkgs/spree/src/provider.ts | 6 ++---- .../internal_pkgs/spree/src/spree.tsx | 2 +- .../internal_pkgs/spree/src/types/provider.d.ts | 12 ------------ 5 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts index 83428c38f3e..110add9b11a 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-checkout.ts @@ -4,8 +4,7 @@ import type { GetCheckoutHook } from '../types/checkout' import Cookies from 'js-cookie' import { useHook, useSWRHook } from '../utils/use-hook' -import { useCommerce } from '..' -import { Provider } from '@plasmicpkgs/commerce' +import { Provider, useCommerce } from '@plasmicpkgs/commerce' export type UseCheckout< H extends SWRHook = SWRHook @@ -19,9 +18,7 @@ export const fetcher: HookFetcherFn = async ({ return cartId ? await fetch(options) : null } -const fn = (provider: Provider) => { - return provider.checkout?.useCheckout! -} +const fn = (provider: Provider) => provider.checkout?.useCheckout! const useCheckout: UseCheckout = (input) => { const hook = useHook(fn) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts index 3534f34ffab..4403c066b6a 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts @@ -1,6 +1,5 @@ import { useCallback } from 'react' -import { Provider } from '@plasmicpkgs/commerce' -import { useCommerce } from '..' +import { Provider, useCommerce } from '@plasmicpkgs/commerce' import type { MutationHook, PickRequired, SWRHook } from './types' import useData from './use-data' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts index 6478afa65ce..4541df48123 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts @@ -7,10 +7,9 @@ import { handler as useSearch } from './product/use-search' import { handler as useProduct } from './product/use-product' import { handler as useCategories } from './site/use-categories' import { handler as useBrands } from './site/use-brands' +import { handler as useCheckout } from './checkout/use-checkout' import { requireConfigValue } from './isomorphic-config' import type { Fetcher, FetcherOptions } from '@plasmicpkgs/commerce' -import useCheckout from './checkout/use-checkout' -import useSubmitCheckout from './commerce/checkout/use-submit-checkout' export const getSpreeProvider = (apiHost: string) => { return { @@ -21,7 +20,7 @@ export const getSpreeProvider = (apiHost: string) => { cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, products: { useSearch, useProduct }, site: { useCategories, useBrands }, - checkout: { useCheckout, useSubmitCheckout }, + checkout: { useCheckout }, } } @@ -39,6 +38,5 @@ export type SpreeProvider = { site: { useCategories: typeof useCategories; useBrands: typeof useBrands } checkout: { useCheckout: typeof useCheckout - useSubmitCheckout: typeof useSubmitCheckout } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx index 0d710203a13..35a01f18a3a 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/spree.tsx @@ -1,6 +1,6 @@ import { useCommerce as useCoreCommerce } from '@plasmicpkgs/commerce' import { getSpreeProvider, SpreeProvider } from './provider' -import { getCommerceProvider as getCoreCommerceProvider } from './commerce' +import { getCommerceProvider as getCoreCommerceProvider } from '@plasmicpkgs/commerce' export type { SpreeProvider } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts b/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts deleted file mode 100644 index 0f0ce7ecc28..00000000000 --- a/platform/canvas-packages/internal_pkgs/spree/src/types/provider.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { MutationHook, SWRHook } from '../commerce/utils/types' -import { Checkout } from '../commerce/types' -import type { Provider as BaseProvider } from '@plasmicpkgs/commerce' - -declare module '@plasmicpkgs/commerce' { - type Provider = BaseProvider & { - checkout?: { - useCheckout?: SWRHook | any - useSubmitCheckout?: MutationHook | any - } - } -} From b3ce66d380a3fd50941ae4a5884485cd4fb5083b Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 11:39:47 +0300 Subject: [PATCH 13/28] fix(spree): rename checkout registration to checkoutProvider --- .../internal_pkgs/spree/src/index.tsx | 6 ++--- ...ckout.tsx => registerCheckoutProvider.tsx} | 23 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) rename platform/canvas-packages/internal_pkgs/spree/src/{registerCheckout.tsx => registerCheckoutProvider.tsx} (58%) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx index 07a3003f48f..996147f23ba 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/index.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/index.tsx @@ -1,13 +1,13 @@ import { Registerable } from './registerable' import { registerCommerceProvider } from './registerCommerceProvider' -import { registerCheckout } from './registerCheckout' +import { registerCheckoutProvider } from './registerCheckoutProvider' export * from './registerable' -export * from './registerCheckout' +export * from './registerCheckoutProvider' export * from './registerCommerceProvider' export * from './spree' export function registerAll(loader?: Registerable) { registerCommerceProvider(loader) - registerCheckout(loader) + registerCheckoutProvider(loader) } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx similarity index 58% rename from platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx rename to platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index d4b26bbeb43..c8efdd681cb 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -6,17 +6,21 @@ import React from 'react' import useCheckout from './checkout/use-checkout' import { DataProvider } from '@plasmicapp/host' -export const checkoutMeta: ComponentMeta> = { +export const checkoutProviderMeta: ComponentMeta< + React.PropsWithChildren +> = { name: 'plasmic-commerce-spree-checkout', - displayName: 'Checkout', + displayName: 'Checkout Provider', description: - 'Shows the checkout order page with the cart items and total price.', - props: {}, + 'Use this to create bespoke checkout UI. Inside Checkout Provider, use dynamic values to access checkout data.', + props: { + children: 'slot', + }, importPath: 'commerce-spree', - importName: 'CheckoutComponent', + importName: 'CheckoutProvider', } -export function CheckoutComponent(props: React.PropsWithChildren) { +export function CheckoutProvider(props: React.PropsWithChildren) { const { data } = useCheckout() return ( @@ -25,11 +29,14 @@ export function CheckoutComponent(props: React.PropsWithChildren) { ) } -export function registerCheckout( +export function registerCheckoutProvider( loader?: Registerable, customCheckoutMeta?: ComponentMeta> ) { const doRegisterComponent: typeof registerComponent = (...args) => loader ? loader.registerComponent(...args) : registerComponent(...args) - doRegisterComponent(CheckoutComponent, customCheckoutMeta ?? checkoutMeta) + doRegisterComponent( + CheckoutProvider, + customCheckoutMeta ?? checkoutProviderMeta + ) } From 0084402fe41851cc3ea5fd738da871a2371c7d8e Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 16:07:06 +0300 Subject: [PATCH 14/28] fix(spree): refactor cart handling and improve checkout integration --- .../internal_pkgs/spree/src/cart/use-cart.tsx | 74 +---------------- .../spree/src/checkout/use-checkout.tsx | 18 ++++- .../spree/src/registerCheckoutProvider.tsx | 1 + .../internal_pkgs/spree/src/utils/get-cart.ts | 80 +++++++++++++++++++ 4 files changed, 101 insertions(+), 72 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/utils/get-cart.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/cart/use-cart.tsx b/platform/canvas-packages/internal_pkgs/spree/src/cart/use-cart.tsx index faf6ba8e38f..f9d10318af8 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/cart/use-cart.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/cart/use-cart.tsx @@ -3,20 +3,9 @@ import type { SWRHook } from '@plasmicpkgs/commerce' import { useCart as useCommerceCart, UseCart } from '@plasmicpkgs/commerce' import type { GetCartHook } from '../types/cart' import normalizeCart from '../utils/normalizations/normalize-cart' -import type { GraphQLFetcherResult } from '../types' -import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' -import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' -import { FetcherError } from '@plasmicpkgs/commerce' -import { setCartToken } from '../utils/tokens/cart-token' -import ensureIToken from '../utils/tokens/ensure-itoken' -import isLoggedIn from '../utils/tokens/is-logged-in' -import createEmptyCart from '../utils/create-empty-cart' -import { requireConfigValue } from '../isomorphic-config' +import getCart from '../utils/get-cart' -const imagesSize = requireConfigValue('imagesSize') as string -const imagesQuality = requireConfigValue('imagesQuality') as number - -export default useCommerceCart as UseCart; +export default useCommerceCart as UseCart // This handler avoids calling /api/cart. // There doesn't seem to be a good reason to call it. @@ -36,64 +25,7 @@ export const handler: SWRHook = { options ) - let spreeCartResponse: IOrder | null - - const token: IToken | undefined = ensureIToken() - - if (!token) { - spreeCartResponse = null - } else { - try { - const { data: spreeCartShowSuccessResponse } = await fetch< - GraphQLFetcherResult - >({ - variables: { - methodPath: 'cart.show', - arguments: [ - token, - { - include: [ - 'line_items', - 'line_items.variant', - 'line_items.variant.product', - 'line_items.variant.product.images', - 'line_items.variant.images', - 'line_items.variant.option_values', - 'line_items.variant.product.option_types', - ].join(','), - image_transformation: { - quality: imagesQuality, - size: imagesSize, - }, - }, - ], - }, - }) - - spreeCartResponse = spreeCartShowSuccessResponse - } catch (fetchCartError) { - if ( - !(fetchCartError instanceof FetcherError) || - fetchCartError.status !== 404 - ) { - throw fetchCartError - } - - spreeCartResponse = null - } - } - - if (!spreeCartResponse || spreeCartResponse?.data.attributes.completed_at) { - const { data: spreeCartCreateSuccessResponse } = await createEmptyCart( - fetch - ) - - spreeCartResponse = spreeCartCreateSuccessResponse - - if (!isLoggedIn()) { - setCartToken(spreeCartResponse.data.attributes.token) - } - } + const spreeCartResponse = await getCart(fetch) return normalizeCart(spreeCartResponse, spreeCartResponse.data) }, diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 64d355785c3..935ff4fb860 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -1,5 +1,7 @@ import { SWRHook } from '@plasmicpkgs/commerce' import useCheckout, { UseCheckout } from '../commerce/checkout/use-checkout' +import type { GraphQLFetcherResult } from '../types' +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' export default useCheckout as UseCheckout @@ -10,7 +12,21 @@ export const handler: SWRHook = { url: 'checkout', query: 'show', }, - async fetcher({ input, options, fetch }) {}, + async fetcher({ input, options, fetch }) { + console.info( + 'useCart fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ) + return fetch>({ + variables: { + methodPath: 'cart.create', + arguments: [token], + }, + }) + }, useHook: ({ useData }) => async (input) => ({}), diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index c8efdd681cb..24db1d32617 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -22,6 +22,7 @@ export const checkoutProviderMeta: ComponentMeta< export function CheckoutProvider(props: React.PropsWithChildren) { const { data } = useCheckout() + console.log('CheckoutProvider', data) return ( {props.children} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/get-cart.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/get-cart.ts new file mode 100644 index 00000000000..d48650f2747 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/get-cart.ts @@ -0,0 +1,80 @@ +import type { GraphQLFetcherResult } from '../types' +import { FetcherError, HookFetcherContext } from '@plasmicpkgs/commerce' +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' +import ensureIToken from './tokens/ensure-itoken' +import createEmptyCart from './create-empty-cart' +import isLoggedIn from './tokens/is-logged-in' +import { setCartToken } from './tokens/cart-token' +import { requireConfigValue } from '../isomorphic-config' + +const imagesSize = requireConfigValue('imagesSize') as string +const imagesQuality = requireConfigValue('imagesQuality') as number + +const getCart = async ( + fetch: HookFetcherContext<{ + data: any + }>['fetch'] +): Promise => { + let spreeCartResponse: IOrder | null + + const token: IToken | undefined = ensureIToken() + + if (!token) { + spreeCartResponse = null + } else { + try { + const { data: spreeCartShowSuccessResponse } = await fetch< + GraphQLFetcherResult + >({ + variables: { + methodPath: 'cart.show', + arguments: [ + token, + { + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types', + ].join(','), + image_transformation: { + quality: imagesQuality, + size: imagesSize, + }, + }, + ], + }, + }) + + spreeCartResponse = spreeCartShowSuccessResponse + } catch (fetchCartError) { + if ( + !(fetchCartError instanceof FetcherError) || + fetchCartError.status !== 404 + ) { + throw fetchCartError + } + + spreeCartResponse = null + } + } + + if (!spreeCartResponse || spreeCartResponse?.data.attributes.completed_at) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart( + fetch + ) + + spreeCartResponse = spreeCartCreateSuccessResponse + + if (!isLoggedIn()) { + setCartToken(spreeCartResponse.data.attributes.token) + } + } + return spreeCartResponse +} + +export default getCart From 6bdd03c6347505c86c69823610d30a813d334bba Mon Sep 17 00:00:00 2001 From: willymwai Date: Thu, 16 Jan 2025 16:26:26 +0300 Subject: [PATCH 15/28] feat(spree): implement checkout submission and enhance checkout hook --- .../spree/src/checkout/use-checkout.tsx | 57 +++++++++++++++---- .../src/checkout/use-submit-checkout.tsx | 38 +++++++++++++ 2 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 935ff4fb860..54dcc338bef 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -1,7 +1,10 @@ import { SWRHook } from '@plasmicpkgs/commerce' import useCheckout, { UseCheckout } from '../commerce/checkout/use-checkout' -import type { GraphQLFetcherResult } from '../types' -import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' +import getCart from '../utils/get-cart' +import normalizeCart from '../utils/normalizations/normalize-cart' +import { useMemo } from 'react' +import { GetCheckoutHook } from '../commerce/types/checkout' +import useSubmitCheckout from './use-submit-checkout' export default useCheckout as UseCheckout @@ -20,14 +23,46 @@ export const handler: SWRHook = { 'options: ', options ) - return fetch>({ - variables: { - methodPath: 'cart.create', - arguments: [token], - }, - }) + const spreeCartResponse = await getCart(fetch) + const cart = normalizeCart(spreeCartResponse, spreeCartResponse.data) + return { + hasPayment: false, + hasShipping: false, + addressId: null, + payments: [], + cardId: null, + lineItems: cart.lineItems, + } + }, + useHook: ({ useData }) => { + const useWrappedHook: ReturnType['useHook']> = ( + input + ) => { + const submit = useSubmitCheckout() + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return response.data?.lineItems?.length ?? 0 + }, + enumerable: true, + }, + submit: { + get() { + return submit + }, + enumerable: true, + }, + }), + [response, submit] + ) + } + + return useWrappedHook }, - useHook: - ({ useData }) => - async (input) => ({}), } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx new file mode 100644 index 00000000000..d8d78ef8bc1 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -0,0 +1,38 @@ +import type { SubmitCheckoutHook } from '@vercel/commerce/types/checkout' +import type { MutationHook } from '@vercel/commerce/utils/types' + +import { useCallback } from 'react' +import useSubmitCheckout, { + UseSubmitCheckout, +} from '@vercel/commerce/checkout/use-submit-checkout' + +export default useSubmitCheckout as UseSubmitCheckout + +export const handler: MutationHook = { + fetchOptions: { + url: '/api/commerce/checkout', + method: 'POST', + }, + async fetcher({ input: item, options, fetch }) { + // @TODO: Make form validations in here, import generic error like import { CommerceError } from '@vercel/commerce/utils/errors' + // Get payment and delivery information in here + + const data = await fetch({ + ...options, + body: { item }, + }) + + return data + }, + useHook: ({ fetch }) => + function useHook() { + return useCallback( + async function onSubmitCheckout(input) { + const data = await fetch({ input }) + + return data + }, + [fetch] + ) + }, +} From 2ce9e647f2735de1660089f51169536dbf00f20a Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 10:24:03 +0300 Subject: [PATCH 16/28] feat(spree): implement checkout submission with address and payment handling --- .../spree/src/checkout/use-checkout.tsx | 2 +- .../src/checkout/use-submit-checkout.tsx | 199 ++++++++++++++++-- .../spree/src/commerce/types/checkout.ts | 27 ++- .../src/commerce/types/customer/address.ts | 8 + 4 files changed, 209 insertions(+), 27 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 54dcc338bef..453532bd5f3 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -17,7 +17,7 @@ export const handler: SWRHook = { }, async fetcher({ input, options, fetch }) { console.info( - 'useCart fetcher called. Configuration: ', + 'useCheckout fetcher called. Configuration: ', 'input: ', input, 'options: ', diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index d8d78ef8bc1..664272e3c61 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -1,38 +1,191 @@ -import type { SubmitCheckoutHook } from '@vercel/commerce/types/checkout' -import type { MutationHook } from '@vercel/commerce/utils/types' +import type { SubmitCheckoutHook } from '../commerce/types/checkout' +import type { MutationHook } from '../commerce/utils/types' -import { useCallback } from 'react' +import { useMemo } from 'react' import useSubmitCheckout, { UseSubmitCheckout, -} from '@vercel/commerce/checkout/use-submit-checkout' +} from '../commerce/checkout/use-submit-checkout' +import ensureIToken from '../utils/tokens/ensure-itoken' +import { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' +import { FetcherError, ValidationError } from '@plasmicpkgs/commerce' +import createEmptyCart from '../utils/create-empty-cart' +import { setCartToken } from '../utils/tokens/cart-token' +import { OrderUpdate } from '@spree/storefront-api-v2-sdk/types/interfaces/Checkout' +import { GraphQLFetcherResult } from '../types' +import { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' +import isLoggedIn from '../utils/tokens/is-logged-in' +import debounce from 'lodash.debounce' +import type { AddressFields } from '../commerce/types/customer/address' +import { IPayment } from '@spree/storefront-api-v2-sdk/types/interfaces/attributes/Payment' +import normalizeCart from '../utils/normalizations/normalize-cart' export default useSubmitCheckout as UseSubmitCheckout +function buildAddress(address: AddressFields) { + return { + firstname: address?.firstName, + lastname: address?.lastName, + address1: address?.streetNumber, + address2: address?.apartments, + city: address?.city, + zipcode: address?.zipCode, + phone: address?.phone, + state_name: address?.state, + country_iso: address?.country, + } +} + export const handler: MutationHook = { + // Provide fetchOptions for SWR cache key fetchOptions: { - url: '/api/commerce/checkout', - method: 'POST', + url: 'checkout', + query: 'orderUpdate', }, - async fetcher({ input: item, options, fetch }) { - // @TODO: Make form validations in here, import generic error like import { CommerceError } from '@vercel/commerce/utils/errors' - // Get payment and delivery information in here + async fetcher({ input, options, fetch }) { + console.info( + 'useSubmitCheckout fetcher called. Configuration: ', + 'input: ', + input, + 'options: ', + options + ) - const data = await fetch({ - ...options, - body: { item }, - }) + let spreeCartResponse: IOrder | null - return data - }, - useHook: ({ fetch }) => - function useHook() { - return useCallback( - async function onSubmitCheckout(input) { - const data = await fetch({ input }) + const { + email, + special_instructions, + billing_address, + shipping_address, + payments, + } = input + + if (!email) { + throw new ValidationError({ + message: 'email needs to be provided.', + }) + } + + let token: IToken | undefined = ensureIToken() + + if (!token) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart( + fetch + ) + + setCartToken(spreeCartCreateSuccessResponse.data.attributes.token) + token = ensureIToken() + } + + try { + const payments_attributes = payments?.map((payment) => ({ + payment_method_id: payment.paymentMethodId, + })) as IPayment[] + + const orderUpdateParameters: OrderUpdate = { + order: { + email, + special_instructions, + bill_address_attributes: buildAddress(billing_address), + ship_address_attributes: buildAddress(shipping_address), + payments_attributes, + }, + } - return data + const { data: spreeSuccessResponse } = await fetch< + GraphQLFetcherResult + >({ + variables: { + methodPath: 'checkout.orderUpdate', + arguments: [token, orderUpdateParameters], + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types', + ].join(','), }, - [fetch] + }) + + spreeCartResponse = spreeSuccessResponse + } catch (updateItemError) { + if ( + updateItemError instanceof FetcherError && + updateItemError.status === 404 + ) { + const { data: spreeRetroactiveCartCreateSuccessResponse } = + await createEmptyCart(fetch) + + if (!isLoggedIn()) { + setCartToken( + spreeRetroactiveCartCreateSuccessResponse.data.attributes.token + ) + } + + // Return an empty cart. The user has to update the item again. + // This is going to be a rare situation. + + spreeCartResponse = spreeRetroactiveCartCreateSuccessResponse + } + + throw updateItemError + } + const cart = normalizeCart(spreeCartResponse, spreeCartResponse.data) + return { + hasPayment: false, + hasShipping: false, + addressId: null, + payments: [], + cardId: null, + lineItems: cart.lineItems, + } + }, + useHook: ({ fetch }) => { + const useWrappedHook: ReturnType< + MutationHook['useHook'] + > = (context) => { + return useMemo( + () => + debounce(async (input: SubmitCheckoutHook['actionInput']) => { + const { + email, + special_instructions, + billing_address, + shipping_address, + payments, + } = input + + if ( + !email && + !special_instructions && + !billing_address && + !shipping_address && + !payments + ) { + throw new ValidationError({ + message: + 'email or special_instructions or billing_address or shipping_address or payments needs to be provided.', + }) + } + + const data = await fetch({ + input: { + email, + special_instructions, + billing_address, + shipping_address, + payments, + }, + }) + return data + }), + [context] ) - }, + } + + return useWrappedHook + }, } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts index 326af252e12..e7bfbb437f6 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -30,7 +30,15 @@ export interface Checkout { lineItems?: LineItem[] } +export interface Payment { + paymentMethodId: string +} + export interface CheckoutBody { + /** + * The email assigned to this cart. + */ + email: string /** * The unique identifier for the cart. */ @@ -39,12 +47,25 @@ export interface CheckoutBody { * The Card information. * @see CardFields */ - card: CardFields + card?: CardFields /** - * The Address information. + * The billing Address information. * @see AddressFields */ - address: AddressFields + billing_address?: AddressFields + /** + * The shipping Address information. + * @see AddressFields + */ + shipping_address?: AddressFields + /** + * The special instructions for the order. + */ + special_instructions?: string + /** + * The list of payments. + */ + payments?: Payment[] } export type SubmitCheckoutHook = { diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts index e6b71ff52c4..4626a423c18 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/customer/address.ts @@ -43,10 +43,18 @@ export interface AddressFields { * The customer's billing address city. */ city: string + /** + * The customer's billing address state. + */ + state: string /** * The customer's billing address country. */ country: string + /** + * The customer's phone number. + */ + phone: string } /** From a59c3927d95f70d17514bf290c06c7549ee46acf Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 10:29:27 +0300 Subject: [PATCH 17/28] fix(spree): remove submit mutation from checkout hook and types --- .../internal_pkgs/spree/src/checkout/use-checkout.tsx | 10 +--------- .../internal_pkgs/spree/src/commerce/types/checkout.ts | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx index 453532bd5f3..b8a605440a1 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-checkout.tsx @@ -4,7 +4,6 @@ import getCart from '../utils/get-cart' import normalizeCart from '../utils/normalizations/normalize-cart' import { useMemo } from 'react' import { GetCheckoutHook } from '../commerce/types/checkout' -import useSubmitCheckout from './use-submit-checkout' export default useCheckout as UseCheckout @@ -38,7 +37,6 @@ export const handler: SWRHook = { const useWrappedHook: ReturnType['useHook']> = ( input ) => { - const submit = useSubmitCheckout() const response = useData({ swrOptions: { revalidateOnFocus: false, ...input?.swrOptions }, }) @@ -52,14 +50,8 @@ export const handler: SWRHook = { }, enumerable: true, }, - submit: { - get() { - return submit - }, - enumerable: true, - }, }), - [response, submit] + [response] ) } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts index e7bfbb437f6..33f7e6e50dc 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -81,7 +81,6 @@ export type GetCheckoutHook = { input: {} fetcherInput: { cartId?: string } swrState: { isEmpty: boolean } - mutations: { submit: UseSubmitCheckout } } export type CheckoutHooks = { From fb6c9dacb414a2b414e2a22b7628861726344c59 Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 15:10:49 +0300 Subject: [PATCH 18/28] fix(spree): fix import typo and update checkout provider integration --- .gitignore | 2 + .../src/checkout/use-submit-checkout.tsx | 2 +- .../commerce/checkout/use-submit-checkout.tsx | 4 +- .../spree/src/commerce/types/checkout.ts | 18 +++--- .../spree/src/commerce/utils/types.ts | 10 +++- .../spree/src/commerce/utils/use-data.tsx | 30 ++++++---- .../spree/src/commerce/utils/use-hook.ts | 20 ++++++- .../internal_pkgs/spree/src/provider.ts | 4 +- .../spree/src/registerCheckoutProvider.tsx | 60 ++++++++++++++++++- .../spree/src/registerCommerceProvider.tsx | 45 +++++++------- 10 files changed, 147 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index d99d128c98e..ac3d3a3192c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ bower_components/ node_modules/ storybook-static/ .nx/ + +.qodo diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index 664272e3c61..d1b0d2d64ca 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -15,7 +15,7 @@ import { GraphQLFetcherResult } from '../types' import { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' import isLoggedIn from '../utils/tokens/is-logged-in' import debounce from 'lodash.debounce' -import type { AddressFields } from '../commerce/types/customer/address' +import type { AddressFields } fm '../commerce/types/customer/address' import { IPayment } from '@spree/storefront-api-v2-sdk/types/interfaces/attributes/Payment' import normalizeCart from '../utils/normalizations/normalize-cart' diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx index b5219c22e7f..18919a87fd1 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/checkout/use-submit-checkout.tsx @@ -6,7 +6,9 @@ import { useHook, useMutationHook } from '../utils/use-hook' import { mutationFetcher } from '../utils/default-fetcher' export type UseSubmitCheckout< - H extends MutationHook = MutationHook + H extends MutationHook< + SubmitCheckoutHook + > = MutationHook > = ReturnType export const fetcher: HookFetcherFn = mutationFetcher diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts index 33f7e6e50dc..286b650374b 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -1,4 +1,3 @@ -import type { UseSubmitCheckout } from '../checkout/use-submit-checkout' import type { AddressFields } from './customer/address' import type { Card, CardFields } from './customer/card' import type { LineItem } from './cart' @@ -68,12 +67,17 @@ export interface CheckoutBody { payments?: Payment[] } -export type SubmitCheckoutHook = { - data: Checkout | null - input?: CheckoutBody - fetcherInput: CheckoutBody - body: { item: CheckoutBody } - actionInput: CheckoutBody +export type CheckoutTypes = { + checkout: Checkout + checkoutBody: CheckoutBody +} + +export type SubmitCheckoutHook = { + data: T['checkout'] | null + input?: T['checkoutBody'] + fetcherInput: T['checkoutBody'] + body: { item: T['checkoutBody'] } + actionInput: T['checkoutBody'] } export type GetCheckoutHook = { diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts index d0045ca8812..9e71d44c68d 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/types.ts @@ -1,6 +1,11 @@ +/* + Forked from https://github.com/vercel/commerce/tree/main/packages/commerce/src + Changes: Added CommerceExtraFeatures and provider to HookFetcherContext +*/ import type { SWRConfiguration } from 'swr' import type { CommerceError } from '@plasmicpkgs/commerce' import type { ResponseState } from './use-data' +import { Provider } from '@plasmicpkgs/commerce' /** * Returns the properties in T with the properties in type K, overriding properties defined in T @@ -48,6 +53,7 @@ export type HookFetcherContext = { >( options: FetcherOptions ) => Promise + provider?: Provider } export type HookFetcherOptions = { method?: string } & ( @@ -55,7 +61,7 @@ export type HookFetcherOptions = { method?: string } & ( | { query?: string; url: string } ) -export type HookInputValue = string | number | boolean | null | undefined +export type HookInputValue = string | number | boolean | undefined export type HookSWRInput = [string, HookInputValue][] @@ -68,7 +74,7 @@ export type HookFunction< ? () => T : Partial extends Input ? (input?: Input) => T - : (input: Input) => T + : (input?: Input) => T export type HookSchemaBase = { // Data obj returned by the hook diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx index 55e839678c5..edd74273648 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-data.tsx @@ -1,15 +1,21 @@ -import useSWR, { SWRResponse } from 'swr' +/* + Forked from https://github.com/vercel/commerce/tree/main/packages/commerce/src + Changes: Replaced useSWR for useMutablePlasmicQueryData and add provider to useData +*/ +import { useMutablePlasmicQueryData } from '@plasmicapp/query' +import { SWRResponse } from 'swr' +import { Provider } from '@plasmicpkgs/commerce' +import defineProperty from './define-property' +import { CommerceError } from '@plasmicpkgs/commerce' import type { - HookSWRInput, - HookFetchInput, - HookFetcherOptions, - HookFetcherFn, Fetcher, - SwrOptions, + HookFetcherFn, + HookFetcherOptions, + HookFetchInput, + HookSWRInput, SWRHookSchemaBase, + SwrOptions, } from './types' -import defineProperty from './define-property' -import { CommerceError } from '@plasmicpkgs/commerce' export type ResponseState = SWRResponse & { isLoading: boolean @@ -22,10 +28,11 @@ export type UseData = ( }, input: HookFetchInput | HookSWRInput, fetcherFn: Fetcher, - swrOptions?: SwrOptions + swrOptions?: SwrOptions, + provider?: Provider ) => ResponseState -const useData: UseData = (options, input, fetcherFn, swrOptions) => { +const useData: UseData = (options, input, fetcherFn, swrOptions, provider) => { const hookInput = Array.isArray(input) ? input : Object.entries(input) const fetcher = async ( url: string, @@ -42,6 +49,7 @@ const useData: UseData = (options, input, fetcherFn, swrOptions) => { return obj }, {}), fetch: fetcherFn, + provider, }) } catch (error) { // SWR will not log errors, but any error that's not an instance @@ -52,7 +60,7 @@ const useData: UseData = (options, input, fetcherFn, swrOptions) => { throw error } } - const response = useSWR( + const response = useMutablePlasmicQueryData( () => { const opts = options.fetchOptions return opts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts index 4403c066b6a..9af47ef9544 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/utils/use-hook.ts @@ -1,3 +1,7 @@ +/* + Forked from https://github.com/vercel/commerce/tree/main/packages/commerce/src + Changes: Add provider to useSWRHook and useMutationHook +*/ import { useCallback } from 'react' import { Provider, useCommerce } from '@plasmicpkgs/commerce' import type { MutationHook, PickRequired, SWRHook } from './types' @@ -8,6 +12,11 @@ export function useFetcher() { return providerRef.current.fetcher ?? fetcherRef.current } +export function useProvider() { + const { providerRef } = useCommerce() + return providerRef.current +} + export function useHook< P extends Provider, H extends MutationHook | SWRHook @@ -21,10 +30,17 @@ export function useSWRHook>( hook: PickRequired ) { const fetcher = useFetcher() + const provider = useProvider() return hook.useHook({ useData(ctx) { - const response = useData(hook, ctx?.input ?? [], fetcher, ctx?.swrOptions) + const response = useData( + hook, + ctx?.input ?? [], + fetcher, + ctx?.swrOptions, + provider + ) return response }, }) @@ -34,6 +50,7 @@ export function useMutationHook>( hook: PickRequired ) { const fetcher = useFetcher() + const provider = useProvider() return hook.useHook({ fetch: useCallback( @@ -42,6 +59,7 @@ export function useMutationHook>( input, options: hook.fetchOptions, fetch: fetcher, + provider, }) }, [fetcher, hook.fetchOptions] diff --git a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts index 4541df48123..1db35db6f8d 100755 --- a/platform/canvas-packages/internal_pkgs/spree/src/provider.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/provider.ts @@ -8,6 +8,7 @@ import { handler as useProduct } from './product/use-product' import { handler as useCategories } from './site/use-categories' import { handler as useBrands } from './site/use-brands' import { handler as useCheckout } from './checkout/use-checkout' +import { handler as useSubmitCheckout } from './checkout/use-submit-checkout' import { requireConfigValue } from './isomorphic-config' import type { Fetcher, FetcherOptions } from '@plasmicpkgs/commerce' @@ -20,7 +21,7 @@ export const getSpreeProvider = (apiHost: string) => { cart: { useCart, useAddItem, useUpdateItem, useRemoveItem }, products: { useSearch, useProduct }, site: { useCategories, useBrands }, - checkout: { useCheckout }, + checkout: { useCheckout, useSubmitCheckout }, } } @@ -38,5 +39,6 @@ export type SpreeProvider = { site: { useCategories: typeof useCategories; useBrands: typeof useBrands } checkout: { useCheckout: typeof useCheckout + useSubmitCheckout: typeof useSubmitCheckout } } diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index 24db1d32617..bcea8e29feb 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -2,9 +2,16 @@ import registerComponent, { ComponentMeta, } from '@plasmicapp/host/registerComponent' import { Registerable } from './registerable' -import React from 'react' +import React, { useMemo } from 'react' import useCheckout from './checkout/use-checkout' -import { DataProvider } from '@plasmicapp/host' +import { + DataProvider, + GlobalActionDict, + GlobalActionsProvider, +} from '@plasmicapp/host' +import useSubmitCheckout from './commerce/checkout/use-submit-checkout' +import type { AddressFields } from './commerce/types/customer/address' +import { Payment } from './commerce/types/checkout' export const checkoutProviderMeta: ComponentMeta< React.PropsWithChildren @@ -16,13 +23,60 @@ export const checkoutProviderMeta: ComponentMeta< props: { children: 'slot', }, + providesData: true, importPath: 'commerce-spree', importName: 'CheckoutProvider', } +interface CheckoutActions extends GlobalActionDict { + submitCheckout: ( + email: string, + special_instructions: string, + billing_address: AddressFields, + shipping_address: AddressFields, + payments: Payment[] + ) => void +} + +export function CheckoutActionsProvider( + props: React.PropsWithChildren<{ + globalContextName: string + }> +) { + const submitCheckout = useSubmitCheckout() + const actions: CheckoutActions = useMemo( + () => ({ + submitCheckout( + email: string, + special_instructions: string, + billing_address: AddressFields, + shipping_address: AddressFields, + payments: Payment[] + ) { + submitCheckout({ + email, + special_instructions, + billing_address, + shipping_address, + payments, + }) + }, + }), + [submitCheckout] + ) + + return ( + + {props.children} + + ) +} + export function CheckoutProvider(props: React.PropsWithChildren) { const { data } = useCheckout() - console.log('CheckoutProvider', data) return ( {props.children} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx index 349c60ecdd7..426e7195ae7 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx @@ -1,49 +1,52 @@ -import { GlobalContextMeta } from "@plasmicapp/host"; -import registerGlobalContext from "@plasmicapp/host/registerGlobalContext"; +import { GlobalContextMeta } from '@plasmicapp/host' +import registerGlobalContext from '@plasmicapp/host/registerGlobalContext' import { CartActionsProvider, globalActionsRegistrations, -} from "@plasmicpkgs/commerce"; -import React from "react"; -import { Registerable } from "./registerable"; -import { getCommerceProvider } from "./spree"; +} from '@plasmicpkgs/commerce' +import React from 'react' +import { Registerable } from './registerable' +import { getCommerceProvider } from './spree' +import { CheckoutActionsProvider } from './registerCheckoutProvider' interface CommerceProviderProps { - children?: React.ReactNode; - apiHost: string; + children?: React.ReactNode + apiHost: string } -const globalContextName = "plasmic-commerce-spree-provider"; +const globalContextName = 'plasmic-commerce-spree-provider' export const commerceProviderMeta: GlobalContextMeta = { name: globalContextName, - displayName: "Spree Provider", + displayName: 'Spree Provider', props: { apiHost: { - type: "string", - defaultValue: "https://olitt.shop", + type: 'string', + defaultValue: 'https://olitt.shop', }, }, ...{ globalActions: globalActionsRegistrations }, - importPath: "commerce-spree", - importName: "CommerceProviderComponent", -}; + importPath: 'commerce-spree', + importName: 'CommerceProviderComponent', +} export function CommerceProviderComponent(props: CommerceProviderProps) { - const { apiHost, children } = props; + const { apiHost, children } = props const CommerceProvider = React.useMemo( () => getCommerceProvider(apiHost), [apiHost] - ); + ) return ( - {children} + + {children} + - ); + ) } export function registerCommerceProvider( @@ -53,9 +56,9 @@ export function registerCommerceProvider( const doRegisterComponent: typeof registerGlobalContext = (...args) => loader ? loader.registerGlobalContext(...args) - : registerGlobalContext(...args); + : registerGlobalContext(...args) doRegisterComponent( CommerceProviderComponent, customCommerceProviderMeta ?? commerceProviderMeta - ); + ) } From e5e34fa849c8164e320fca0412c17b1c4c412f50 Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 15:11:44 +0300 Subject: [PATCH 19/28] fix(spree): fix import typo in AddressFields path --- .../internal_pkgs/spree/src/checkout/use-submit-checkout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index d1b0d2d64ca..664272e3c61 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -15,7 +15,7 @@ import { GraphQLFetcherResult } from '../types' import { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' import isLoggedIn from '../utils/tokens/is-logged-in' import debounce from 'lodash.debounce' -import type { AddressFields } fm '../commerce/types/customer/address' +import type { AddressFields } from '../commerce/types/customer/address' import { IPayment } from '@spree/storefront-api-v2-sdk/types/interfaces/attributes/Payment' import normalizeCart from '../utils/normalizations/normalize-cart' From 0ae98d9b40dfb71d08fbba7604a6bfa82f1996f3 Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 15:39:10 +0300 Subject: [PATCH 20/28] feat(spree): add global actions registration for checkout submission --- .../spree/src/registerCheckoutProvider.tsx | 39 +++++++++++++++++++ .../spree/src/registerCommerceProvider.tsx | 10 ++--- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index bcea8e29feb..21155e94930 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -12,6 +12,8 @@ import { import useSubmitCheckout from './commerce/checkout/use-submit-checkout' import type { AddressFields } from './commerce/types/customer/address' import { Payment } from './commerce/types/checkout' +import { globalActionsRegistrations as baseGlobalActionsRegistrations } from '@plasmicpkgs/commerce' +import { GlobalActionRegistration } from '@plasmicapp/host/registerGlobalContext' export const checkoutProviderMeta: ComponentMeta< React.PropsWithChildren @@ -95,3 +97,40 @@ export function registerCheckoutProvider( customCheckoutMeta ?? checkoutProviderMeta ) } + +export const globalActionsRegistrations: Record< + string, + GlobalActionRegistration +> = { + ...baseGlobalActionsRegistrations, + submitCheckout: { + displayName: 'Submit checkout', + parameters: [ + { + name: 'email', + displayName: 'Email', + type: 'string', + }, + { + name: 'special_instructions', + displayName: 'Special instructions', + type: 'string', + }, + { + name: 'billing_address', + displayName: 'Billing address', + type: 'object', + }, + { + name: 'shipping_address', + displayName: 'Shipping address', + type: 'object', + }, + { + name: 'payments', + displayName: 'Payments', + type: 'object', + }, + ], + }, +} diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx index 426e7195ae7..bf325b18493 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCommerceProvider.tsx @@ -1,13 +1,13 @@ import { GlobalContextMeta } from '@plasmicapp/host' import registerGlobalContext from '@plasmicapp/host/registerGlobalContext' -import { - CartActionsProvider, - globalActionsRegistrations, -} from '@plasmicpkgs/commerce' +import { CartActionsProvider } from '@plasmicpkgs/commerce' import React from 'react' import { Registerable } from './registerable' import { getCommerceProvider } from './spree' -import { CheckoutActionsProvider } from './registerCheckoutProvider' +import { + CheckoutActionsProvider, + globalActionsRegistrations, +} from './registerCheckoutProvider' interface CommerceProviderProps { children?: React.ReactNode From 6833fc762262e0d7f966a0fe8c945f92285b5144 Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 15:57:19 +0300 Subject: [PATCH 21/28] refactor(spree): extract checkout submission logic to separate utility --- .../src/checkout/use-submit-checkout.tsx | 122 +--------------- .../spree/src/utils/submit-checkout.ts | 133 ++++++++++++++++++ 2 files changed, 136 insertions(+), 119 deletions(-) create mode 100644 platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index 664272e3c61..a7bca858e88 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -5,36 +5,12 @@ import { useMemo } from 'react' import useSubmitCheckout, { UseSubmitCheckout, } from '../commerce/checkout/use-submit-checkout' -import ensureIToken from '../utils/tokens/ensure-itoken' -import { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' -import { FetcherError, ValidationError } from '@plasmicpkgs/commerce' -import createEmptyCart from '../utils/create-empty-cart' -import { setCartToken } from '../utils/tokens/cart-token' -import { OrderUpdate } from '@spree/storefront-api-v2-sdk/types/interfaces/Checkout' -import { GraphQLFetcherResult } from '../types' -import { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' -import isLoggedIn from '../utils/tokens/is-logged-in' +import { ValidationError } from '@plasmicpkgs/commerce' import debounce from 'lodash.debounce' -import type { AddressFields } from '../commerce/types/customer/address' -import { IPayment } from '@spree/storefront-api-v2-sdk/types/interfaces/attributes/Payment' -import normalizeCart from '../utils/normalizations/normalize-cart' +import submitCheckout from '../utils/submit-checkout' export default useSubmitCheckout as UseSubmitCheckout -function buildAddress(address: AddressFields) { - return { - firstname: address?.firstName, - lastname: address?.lastName, - address1: address?.streetNumber, - address2: address?.apartments, - city: address?.city, - zipcode: address?.zipCode, - phone: address?.phone, - state_name: address?.state, - country_iso: address?.country, - } -} - export const handler: MutationHook = { // Provide fetchOptions for SWR cache key fetchOptions: { @@ -49,99 +25,7 @@ export const handler: MutationHook = { 'options: ', options ) - - let spreeCartResponse: IOrder | null - - const { - email, - special_instructions, - billing_address, - shipping_address, - payments, - } = input - - if (!email) { - throw new ValidationError({ - message: 'email needs to be provided.', - }) - } - - let token: IToken | undefined = ensureIToken() - - if (!token) { - const { data: spreeCartCreateSuccessResponse } = await createEmptyCart( - fetch - ) - - setCartToken(spreeCartCreateSuccessResponse.data.attributes.token) - token = ensureIToken() - } - - try { - const payments_attributes = payments?.map((payment) => ({ - payment_method_id: payment.paymentMethodId, - })) as IPayment[] - - const orderUpdateParameters: OrderUpdate = { - order: { - email, - special_instructions, - bill_address_attributes: buildAddress(billing_address), - ship_address_attributes: buildAddress(shipping_address), - payments_attributes, - }, - } - - const { data: spreeSuccessResponse } = await fetch< - GraphQLFetcherResult - >({ - variables: { - methodPath: 'checkout.orderUpdate', - arguments: [token, orderUpdateParameters], - include: [ - 'line_items', - 'line_items.variant', - 'line_items.variant.product', - 'line_items.variant.product.images', - 'line_items.variant.images', - 'line_items.variant.option_values', - 'line_items.variant.product.option_types', - ].join(','), - }, - }) - - spreeCartResponse = spreeSuccessResponse - } catch (updateItemError) { - if ( - updateItemError instanceof FetcherError && - updateItemError.status === 404 - ) { - const { data: spreeRetroactiveCartCreateSuccessResponse } = - await createEmptyCart(fetch) - - if (!isLoggedIn()) { - setCartToken( - spreeRetroactiveCartCreateSuccessResponse.data.attributes.token - ) - } - - // Return an empty cart. The user has to update the item again. - // This is going to be a rare situation. - - spreeCartResponse = spreeRetroactiveCartCreateSuccessResponse - } - - throw updateItemError - } - const cart = normalizeCart(spreeCartResponse, spreeCartResponse.data) - return { - hasPayment: false, - hasShipping: false, - addressId: null, - payments: [], - cardId: null, - lineItems: cart.lineItems, - } + return await submitCheckout(fetch, input) }, useHook: ({ fetch }) => { const useWrappedHook: ReturnType< diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts new file mode 100644 index 00000000000..d49c7b3b6a9 --- /dev/null +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts @@ -0,0 +1,133 @@ +import type { GraphQLFetcherResult } from '../types' +import { + FetcherError, + HookFetcherContext, + ValidationError, +} from '@plasmicpkgs/commerce' +import type { IOrder } from '@spree/storefront-api-v2-sdk/types/interfaces/Order' +import type { IToken } from '@spree/storefront-api-v2-sdk/types/interfaces/Token' +import ensureIToken from './tokens/ensure-itoken' +import createEmptyCart from './create-empty-cart' +import isLoggedIn from './tokens/is-logged-in' +import { setCartToken } from './tokens/cart-token' +import { IPayment } from '@spree/storefront-api-v2-sdk/types/interfaces/attributes/Payment' +import { OrderUpdate } from '@spree/storefront-api-v2-sdk/types/interfaces/Checkout' +import normalizeCart from './normalizations/normalize-cart' +import type { AddressFields } from '../commerce/types/customer/address' +import { Checkout, CheckoutBody } from '../commerce/types/checkout' + +function buildAddress(address: AddressFields) { + return { + firstname: address?.firstName, + lastname: address?.lastName, + address1: address?.streetNumber, + address2: address?.apartments, + city: address?.city, + zipcode: address?.zipCode, + phone: address?.phone, + state_name: address?.state, + country_iso: address?.country, + } +} + +const submitCheckout = async ( + fetch: HookFetcherContext<{ + data: any + }>['fetch'], + input: CheckoutBody +): Promise => { + let spreeCartResponse: IOrder | null + + const { + email, + special_instructions, + billing_address, + shipping_address, + payments, + } = input + + if (!email) { + throw new ValidationError({ + message: 'email needs to be provided.', + }) + } + + let token: IToken | undefined = ensureIToken() + + if (!token) { + const { data: spreeCartCreateSuccessResponse } = await createEmptyCart( + fetch + ) + + setCartToken(spreeCartCreateSuccessResponse.data.attributes.token) + token = ensureIToken() + } + + try { + const payments_attributes = payments?.map((payment) => ({ + payment_method_id: payment.paymentMethodId, + })) as IPayment[] + + const orderUpdateParameters: OrderUpdate = { + order: { + email, + special_instructions, + bill_address_attributes: buildAddress(billing_address), + ship_address_attributes: buildAddress(shipping_address), + payments_attributes, + }, + } + + const { data: spreeSuccessResponse } = await fetch< + GraphQLFetcherResult + >({ + variables: { + methodPath: 'checkout.orderUpdate', + arguments: [token, orderUpdateParameters], + include: [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types', + ].join(','), + }, + }) + + spreeCartResponse = spreeSuccessResponse + } catch (updateItemError) { + if ( + updateItemError instanceof FetcherError && + updateItemError.status === 404 + ) { + const { data: spreeRetroactiveCartCreateSuccessResponse } = + await createEmptyCart(fetch) + + if (!isLoggedIn()) { + setCartToken( + spreeRetroactiveCartCreateSuccessResponse.data.attributes.token + ) + } + + // Return an empty cart. The user has to update the item again. + // This is going to be a rare situation. + + spreeCartResponse = spreeRetroactiveCartCreateSuccessResponse + } + + throw updateItemError + } + const cart = normalizeCart(spreeCartResponse, spreeCartResponse.data) + return { + hasPayment: false, + hasShipping: false, + addressId: null, + payments: [], + cardId: null, + lineItems: cart.lineItems, + } +} + +export default submitCheckout From a159b57cd7f170fccdb7434cce3461a4314fc69b Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 16:06:21 +0300 Subject: [PATCH 22/28] refactor(spree): optimize checkout submission with useCallback and data mutation --- .../src/checkout/use-submit-checkout.tsx | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index a7bca858e88..18d0db3e1d1 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -1,13 +1,13 @@ import type { SubmitCheckoutHook } from '../commerce/types/checkout' import type { MutationHook } from '../commerce/utils/types' -import { useMemo } from 'react' +import { useCallback } from 'react' import useSubmitCheckout, { UseSubmitCheckout, } from '../commerce/checkout/use-submit-checkout' import { ValidationError } from '@plasmicpkgs/commerce' -import debounce from 'lodash.debounce' import submitCheckout from '../utils/submit-checkout' +import useCheckout from './use-checkout' export default useSubmitCheckout as UseSubmitCheckout @@ -27,49 +27,52 @@ export const handler: MutationHook = { ) return await submitCheckout(fetch, input) }, + useHook: ({ fetch }) => { const useWrappedHook: ReturnType< MutationHook['useHook'] - > = (context) => { - return useMemo( - () => - debounce(async (input: SubmitCheckoutHook['actionInput']) => { - const { + > = () => { + const { mutate } = useCheckout() + + return useCallback( + async (input) => { + const { + email, + special_instructions, + billing_address, + shipping_address, + payments, + } = input + + if ( + !email && + !special_instructions && + !billing_address && + !shipping_address && + !payments + ) { + throw new ValidationError({ + message: + 'email or special_instructions or billing_address or shipping_address or payments needs to be provided.', + }) + } + const data = await fetch({ + input: { email, special_instructions, billing_address, shipping_address, payments, - } = input + }, + }) - if ( - !email && - !special_instructions && - !billing_address && - !shipping_address && - !payments - ) { - throw new ValidationError({ - message: - 'email or special_instructions or billing_address or shipping_address or payments needs to be provided.', - }) - } + await mutate(data, false) - const data = await fetch({ - input: { - email, - special_instructions, - billing_address, - shipping_address, - payments, - }, - }) - return data - }), - [context] + return data + }, + [mutate] ) } - return useWrappedHook }, } From 4effd31b43d09136a913b508b8734f562554da83 Mon Sep 17 00:00:00 2001 From: willymwai Date: Fri, 17 Jan 2025 16:26:31 +0300 Subject: [PATCH 23/28] feat(spree): add onSuccessAction support for checkout submission --- .../src/checkout/use-submit-checkout.tsx | 2 ++ .../spree/src/commerce/types/checkout.ts | 1 + .../spree/src/utils/submit-checkout.ts | 35 +++++++++++++------ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx index 18d0db3e1d1..4f1009ad89c 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/checkout/use-submit-checkout.tsx @@ -42,6 +42,7 @@ export const handler: MutationHook = { billing_address, shipping_address, payments, + onSuccessAction, } = input if ( @@ -63,6 +64,7 @@ export const handler: MutationHook = { billing_address, shipping_address, payments, + onSuccessAction, }, }) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts index 286b650374b..e85fdfc38c2 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -65,6 +65,7 @@ export interface CheckoutBody { * The list of payments. */ payments?: Payment[] + onSuccessAction?: 'next' | 'advance' | 'complete' | null } export type CheckoutTypes = { diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts index d49c7b3b6a9..4fd37983998 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts @@ -78,25 +78,40 @@ const submitCheckout = async ( }, } + const includeParams = [ + 'line_items', + 'line_items.variant', + 'line_items.variant.product', + 'line_items.variant.product.images', + 'line_items.variant.images', + 'line_items.variant.option_values', + 'line_items.variant.product.option_types', + ].join(',') + const { data: spreeSuccessResponse } = await fetch< GraphQLFetcherResult >({ variables: { methodPath: 'checkout.orderUpdate', arguments: [token, orderUpdateParameters], - include: [ - 'line_items', - 'line_items.variant', - 'line_items.variant.product', - 'line_items.variant.product.images', - 'line_items.variant.images', - 'line_items.variant.option_values', - 'line_items.variant.product.option_types', - ].join(','), + include: includeParams, }, }) - spreeCartResponse = spreeSuccessResponse + if (input.onSuccessAction) { + const { data: checkoutActionResponse } = await fetch< + GraphQLFetcherResult + >({ + variables: { + methodPath: `checkout.${input.onSuccessAction}`, + arguments: [token], + include: includeParams, + }, + }) + spreeCartResponse = checkoutActionResponse + } else { + spreeCartResponse = spreeSuccessResponse + } } catch (updateItemError) { if ( updateItemError instanceof FetcherError && From f420042a4253629408cce76ae468e705c784fb94 Mon Sep 17 00:00:00 2001 From: willymwai Date: Sat, 18 Jan 2025 07:32:00 +0300 Subject: [PATCH 24/28] feat(spree): add onSuccessAction parameter to checkout submission --- .../internal_pkgs/spree/src/registerCheckoutProvider.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index 21155e94930..c2dd09309e2 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -131,6 +131,15 @@ export const globalActionsRegistrations: Record< displayName: 'Payments', type: 'object', }, + { + name: 'onSuccessAction', + displayName: 'On success action', + type: { + type: 'choice', + multiSelect: false, + options: ['next', 'advance', 'complete'], + }, + }, ], }, } From f3278119a467e6bcf8e622fdec2783d60fd9457b Mon Sep 17 00:00:00 2001 From: willymwai Date: Sat, 18 Jan 2025 09:04:46 +0300 Subject: [PATCH 25/28] fix(spree): improve checkout submission with include params and onSuccessAction options --- .../spree/src/registerCheckoutProvider.tsx | 7 ++++- .../spree/src/utils/submit-checkout.ts | 27 ++++++++++--------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index c2dd09309e2..ef12e5daf42 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -137,7 +137,12 @@ export const globalActionsRegistrations: Record< type: { type: 'choice', multiSelect: false, - options: ['next', 'advance', 'complete'], + options: [ + { value: 'next', label: 'Next' }, + { value: 'advance', label: 'Advance' }, + { value: 'complete', label: 'Complete' }, + { value: 'null', label: 'None' }, + ], }, }, ], diff --git a/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts index 4fd37983998..b9754d6aa79 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/utils/submit-checkout.ts @@ -44,6 +44,7 @@ const submitCheckout = async ( billing_address, shipping_address, payments, + onSuccessAction, } = input if (!email) { @@ -68,16 +69,6 @@ const submitCheckout = async ( payment_method_id: payment.paymentMethodId, })) as IPayment[] - const orderUpdateParameters: OrderUpdate = { - order: { - email, - special_instructions, - bill_address_attributes: buildAddress(billing_address), - ship_address_attributes: buildAddress(shipping_address), - payments_attributes, - }, - } - const includeParams = [ 'line_items', 'line_items.variant', @@ -88,22 +79,32 @@ const submitCheckout = async ( 'line_items.variant.product.option_types', ].join(',') + const orderUpdateParameters: OrderUpdate = { + order: { + email, + special_instructions, + bill_address_attributes: buildAddress(billing_address), + ship_address_attributes: buildAddress(shipping_address), + payments_attributes, + }, + include: includeParams, + } + const { data: spreeSuccessResponse } = await fetch< GraphQLFetcherResult >({ variables: { methodPath: 'checkout.orderUpdate', arguments: [token, orderUpdateParameters], - include: includeParams, }, }) - if (input.onSuccessAction) { + if (onSuccessAction) { const { data: checkoutActionResponse } = await fetch< GraphQLFetcherResult >({ variables: { - methodPath: `checkout.${input.onSuccessAction}`, + methodPath: `checkout.${onSuccessAction}`, arguments: [token], include: includeParams, }, From ba416615041d3c0b125675b9bc5b03c1b5258f53 Mon Sep 17 00:00:00 2001 From: willymwai Date: Sat, 18 Jan 2025 09:44:20 +0300 Subject: [PATCH 26/28] feat(spree): enhance address fields validation in checkout submission --- .../spree/src/registerCheckoutProvider.tsx | 71 +++++++++++++++++-- 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index ef12e5daf42..0e5ad0b354f 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -36,7 +36,8 @@ interface CheckoutActions extends GlobalActionDict { special_instructions: string, billing_address: AddressFields, shipping_address: AddressFields, - payments: Payment[] + payments: Payment[], + onSuccessAction: 'next' | 'advance' | 'complete' | null ) => void } @@ -53,7 +54,8 @@ export function CheckoutActionsProvider( special_instructions: string, billing_address: AddressFields, shipping_address: AddressFields, - payments: Payment[] + payments: Payment[], + onSuccessAction: 'next' | 'advance' | 'complete' | null ) { submitCheckout({ email, @@ -61,6 +63,7 @@ export function CheckoutActionsProvider( billing_address, shipping_address, payments, + onSuccessAction, }) }, }), @@ -98,6 +101,60 @@ export function registerCheckoutProvider( ) } +const addressFields: Record = { + type: { + displayName: 'Type', + type: { + type: 'choice', + multiSelect: false, + options: [ + { value: 'billing', label: 'Billing' }, + { value: 'shipping', label: 'Shipping' }, + ], + }, + }, + firstName: { + displayName: 'First name', + type: 'string', + }, + lastName: { + displayName: 'Last name', + type: 'string', + }, + company: { + displayName: 'Company', + type: 'string', + }, + streetNumber: { + displayName: 'Street number', + type: 'string', + }, + apartments: { + displayName: 'Apartments', + type: 'string', + }, + zipCode: { + displayName: 'Zip code', + type: 'string', + }, + city: { + displayName: 'City', + type: 'string', + }, + state: { + displayName: 'State', + type: 'string', + }, + country: { + displayName: 'Country', + type: 'string', + }, + phone: { + displayName: 'Phone', + type: 'string', + }, +} + export const globalActionsRegistrations: Record< string, GlobalActionRegistration @@ -119,12 +176,18 @@ export const globalActionsRegistrations: Record< { name: 'billing_address', displayName: 'Billing address', - type: 'object', + type: { + type: 'object', + fields: addressFields, + }, }, { name: 'shipping_address', displayName: 'Shipping address', - type: 'object', + type: { + type: 'object', + fields: addressFields, + }, }, { name: 'payments', From cb8414362623dcff6cc533c7248d0046fba4bd5c Mon Sep 17 00:00:00 2001 From: willymwai Date: Sat, 18 Jan 2025 09:55:07 +0300 Subject: [PATCH 27/28] fix(spree): update onSuccessAction value from 'next' to 'orderNext' --- .../internal_pkgs/spree/src/commerce/types/checkout.ts | 2 +- .../internal_pkgs/spree/src/registerCheckoutProvider.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts index e85fdfc38c2..002cb24c5d2 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts +++ b/platform/canvas-packages/internal_pkgs/spree/src/commerce/types/checkout.ts @@ -65,7 +65,7 @@ export interface CheckoutBody { * The list of payments. */ payments?: Payment[] - onSuccessAction?: 'next' | 'advance' | 'complete' | null + onSuccessAction?: 'orderNext' | 'advance' | 'complete' | null } export type CheckoutTypes = { diff --git a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx index 0e5ad0b354f..8fe696cbeeb 100644 --- a/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx +++ b/platform/canvas-packages/internal_pkgs/spree/src/registerCheckoutProvider.tsx @@ -37,7 +37,7 @@ interface CheckoutActions extends GlobalActionDict { billing_address: AddressFields, shipping_address: AddressFields, payments: Payment[], - onSuccessAction: 'next' | 'advance' | 'complete' | null + onSuccessAction: 'orderNext' | 'advance' | 'complete' | null ) => void } @@ -55,7 +55,7 @@ export function CheckoutActionsProvider( billing_address: AddressFields, shipping_address: AddressFields, payments: Payment[], - onSuccessAction: 'next' | 'advance' | 'complete' | null + onSuccessAction: 'orderNext' | 'advance' | 'complete' | null ) { submitCheckout({ email, @@ -201,7 +201,7 @@ export const globalActionsRegistrations: Record< type: 'choice', multiSelect: false, options: [ - { value: 'next', label: 'Next' }, + { value: 'orderNext', label: 'Next' }, { value: 'advance', label: 'Advance' }, { value: 'complete', label: 'Complete' }, { value: 'null', label: 'None' }, From b9362c2760ff36f199e33643b8e3c0cb995d569f Mon Sep 17 00:00:00 2001 From: willymwai Date: Sat, 18 Jan 2025 10:01:40 +0300 Subject: [PATCH 28/28] feat(spree): bump commerce-spree package version to 0.1.0 --- platform/canvas-packages/internal_pkgs/spree/package.json | 2 +- platform/canvas-packages/package.json | 2 +- platform/canvas-packages/yarn.lock | 8 ++++---- platform/loader-bundle-env/package.json | 2 +- platform/loader-bundle-env/yarn.lock | 8 ++++---- platform/wab/.tmp/loader-bundle-env/package.json | 2 +- platform/wab/.tmp/loader-bundle-env/yarn.lock | 8 ++++---- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/platform/canvas-packages/internal_pkgs/spree/package.json b/platform/canvas-packages/internal_pkgs/spree/package.json index 68e4878d670..f7e143147b3 100644 --- a/platform/canvas-packages/internal_pkgs/spree/package.json +++ b/platform/canvas-packages/internal_pkgs/spree/package.json @@ -1,6 +1,6 @@ { "name": "commerce-spree", - "version": "0.0.31", + "version": "0.1.0", "description": "Plasmic registration calls for spree commerce provider", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/platform/canvas-packages/package.json b/platform/canvas-packages/package.json index 6666dd769ce..97e5494d31e 100644 --- a/platform/canvas-packages/package.json +++ b/platform/canvas-packages/package.json @@ -70,7 +70,7 @@ "axios": "^1.5.1", "chart.js": "^4.2.1", "classnames": "^2.3.2", - "commerce-spree": "^0.0.31", + "commerce-spree": "^0.1.0", "copy-to-clipboard": "^3.3.3", "date-fns": "^2.30.0", "dayjs": "^1.11.10", diff --git a/platform/canvas-packages/yarn.lock b/platform/canvas-packages/yarn.lock index c658e8482ea..1025b21d304 100644 --- a/platform/canvas-packages/yarn.lock +++ b/platform/canvas-packages/yarn.lock @@ -7284,10 +7284,10 @@ commander@^7.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== -commerce-spree@^0.0.31: - version "0.0.31" - resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.31.tgz#8b70d455021f3fee89ab0a4bb435fb4b64e63a2d" - integrity sha512-WM8v32Q8Q0FVPY6OwHG30yFhsH0hHoSAPtvKwYEAt5lXRW1T8bqO0Vq3JguGBmaw8C3OGFfEU/dab22mtxdjig== +commerce-spree@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.1.0.tgz#7986bf8cdfb1fd1fbf58dcc7788b65c17e27b4ab" + integrity sha512-Yu1dt5E7jo56+ycEe5Bw1wvarGH1JbsdJKkQRm2gijdz1gQZ+3LTeEncNzwi4ZzCFyIQJeyNweEOsvgykGI/sQ== dependencies: "@plasmicpkgs/commerce" "0.0.205" "@spree/storefront-api-v2-sdk" "^5.1.1" diff --git a/platform/loader-bundle-env/package.json b/platform/loader-bundle-env/package.json index 905b8c2cd37..ac40f9eb731 100644 --- a/platform/loader-bundle-env/package.json +++ b/platform/loader-bundle-env/package.json @@ -26,7 +26,7 @@ "@plasmicpkgs/commerce-saleor": "^0.0.170", "@plasmicpkgs/commerce-shopify": "^0.0.213", "@plasmicpkgs/commerce-swell": "^0.0.215", - "commerce-spree": "^0.0.31", + "commerce-spree": "^0.1.0", "@plasmicpkgs/framer-motion": "^0.0.206", "@plasmicpkgs/lottie-react": "^0.0.199", "@plasmicpkgs/plasmic-basic-components": "^0.0.231", diff --git a/platform/loader-bundle-env/yarn.lock b/platform/loader-bundle-env/yarn.lock index e6a5be5c110..f5277eac5bb 100644 --- a/platform/loader-bundle-env/yarn.lock +++ b/platform/loader-bundle-env/yarn.lock @@ -6664,10 +6664,10 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commerce-spree@^0.0.31: - version "0.0.31" - resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.31.tgz#8b70d455021f3fee89ab0a4bb435fb4b64e63a2d" - integrity sha512-WM8v32Q8Q0FVPY6OwHG30yFhsH0hHoSAPtvKwYEAt5lXRW1T8bqO0Vq3JguGBmaw8C3OGFfEU/dab22mtxdjig== +commerce-spree@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.1.0.tgz#7986bf8cdfb1fd1fbf58dcc7788b65c17e27b4ab" + integrity sha512-Yu1dt5E7jo56+ycEe5Bw1wvarGH1JbsdJKkQRm2gijdz1gQZ+3LTeEncNzwi4ZzCFyIQJeyNweEOsvgykGI/sQ== dependencies: "@plasmicpkgs/commerce" "0.0.205" "@spree/storefront-api-v2-sdk" "^5.1.1" diff --git a/platform/wab/.tmp/loader-bundle-env/package.json b/platform/wab/.tmp/loader-bundle-env/package.json index 3711ba6a779..1b614e4fdc7 100644 --- a/platform/wab/.tmp/loader-bundle-env/package.json +++ b/platform/wab/.tmp/loader-bundle-env/package.json @@ -26,7 +26,7 @@ "@plasmicpkgs/commerce-saleor": "^0.0.169", "@plasmicpkgs/commerce-shopify": "^0.0.212", "@plasmicpkgs/commerce-swell": "^0.0.214", - "commerce-spree": "^0.0.30", + "commerce-spree": "^0.1.0", "@plasmicpkgs/framer-motion": "^0.0.205", "@plasmicpkgs/lottie-react": "^0.0.197", "@plasmicpkgs/plasmic-basic-components": "^0.0.230", diff --git a/platform/wab/.tmp/loader-bundle-env/yarn.lock b/platform/wab/.tmp/loader-bundle-env/yarn.lock index 7e0089e0cac..490130ef6e3 100644 --- a/platform/wab/.tmp/loader-bundle-env/yarn.lock +++ b/platform/wab/.tmp/loader-bundle-env/yarn.lock @@ -6651,10 +6651,10 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commerce-spree@^0.0.30: - version "0.0.30" - resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.0.30.tgz#d44248f6a109cd1bd9a7403bdd06704a1f0c2a98" - integrity sha512-NQHylP/9pwNMkl0HYfYXNNh6G7b0QXB9wwQHWrYRrgDouAF1sP3vcIAKthOba1EwCAkZnhPc/CKBstQAC0sDfw== +commerce-spree@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/commerce-spree/-/commerce-spree-0.1.0.tgz#7986bf8cdfb1fd1fbf58dcc7788b65c17e27b4ab" + integrity sha512-Yu1dt5E7jo56+ycEe5Bw1wvarGH1JbsdJKkQRm2gijdz1gQZ+3LTeEncNzwi4ZzCFyIQJeyNweEOsvgykGI/sQ== dependencies: "@plasmicpkgs/commerce" "0.0.205" "@spree/storefront-api-v2-sdk" "^5.1.1"