diff --git a/framework/commerce/types/checkout.ts b/framework/commerce/types/checkout.ts index 58b895368..27b441f03 100644 --- a/framework/commerce/types/checkout.ts +++ b/framework/commerce/types/checkout.ts @@ -46,7 +46,7 @@ export type SubmitCheckoutHandler = export type CheckoutHandlers = { getCheckout: GetCheckoutHandler - submitCheckout?: SubmitCheckoutHandler + submitCheckout: SubmitCheckoutHandler } export type CheckoutSchema = { diff --git a/framework/commerce/types/customer/address.ts b/framework/commerce/types/customer/address.ts index 5b6ca4b49..8dc6ffc0d 100644 --- a/framework/commerce/types/customer/address.ts +++ b/framework/commerce/types/customer/address.ts @@ -1,41 +1,46 @@ export interface Address { - id: string; - mask: string; + id: string + mask: string } export interface AddressFields { - type: string; - firstName: string; - lastName: string; - company: string; - streetNumber: string; - apartments: string; - zipCode: string; - city: string; - country: string; + type: string + firstName: string + lastName: string + company: string + streetNumber: string + apartments: string + zipCode: string + city: string + country: string } export type CustomerAddressTypes = { - address?: Address; - fields: AddressFields; + address?: Address + fields: AddressFields } -export type GetAddressesHook = { - data: T['address'] | null +export type GetAddressesHook< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { + data: T['address'][] | null input: {} fetcherInput: { cartId?: string } swrState: { isEmpty: boolean } } -export type AddItemHook = { - data: T['address'] - input?: T['fields'] - fetcherInput: T['fields'] - body: { item: T['fields'] } - actionInput: T['fields'] -} +export type AddItemHook = + { + data: T['address'] + input?: T['fields'] + fetcherInput: T['fields'] + body: { item: T['fields'] } + actionInput: T['fields'] + } -export type UpdateItemHook = { +export type UpdateItemHook< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { data: T['address'] | null input: { item?: T['fields']; wait?: number } fetcherInput: { itemId: string; item: T['fields'] } @@ -43,49 +48,62 @@ export type UpdateItemHook = { +export type RemoveItemHook< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { data: T['address'] | null - input: { item?: T['fields'] } + input: { item?: T['address'] } fetcherInput: { itemId: string } body: { itemId: string } actionInput: { id: string } } -export type CustomerAddressHooks = { +export type CustomerAddressHooks< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { getAddresses: GetAddressesHook addItem: AddItemHook updateItem: UpdateItemHook removeItem: RemoveItemHook } -export type AddresssHandler = GetAddressesHook & { +export type AddressHandler< + T extends CustomerAddressTypes = CustomerAddressTypes +> = GetAddressesHook & { body: { cartId?: string } } -export type AddItemHandler = AddItemHook & { +export type AddItemHandler< + T extends CustomerAddressTypes = CustomerAddressTypes +> = AddItemHook & { body: { cartId: string } } -export type UpdateItemHandler = - UpdateItemHook & { - data: T['address'] - body: { cartId: string } - } +export type UpdateItemHandler< + T extends CustomerAddressTypes = CustomerAddressTypes +> = UpdateItemHook & { + data: T['address'] + body: { cartId: string } +} -export type RemoveItemHandler = - RemoveItemHook & { - body: { cartId: string } - } +export type RemoveItemHandler< + T extends CustomerAddressTypes = CustomerAddressTypes +> = RemoveItemHook & { + body: { cartId: string } +} - -export type CustomerAddressHandlers = { +export type CustomerAddressHandlers< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { getAddresses: GetAddressesHook addItem: AddItemHandler updateItem: UpdateItemHandler removeItem: RemoveItemHandler } -export type CustomerAddressSchema = { +export type CustomerAddressSchema< + T extends CustomerAddressTypes = CustomerAddressTypes +> = { endpoint: { options: {} handlers: CustomerAddressHandlers diff --git a/framework/commerce/types/customer/card.ts b/framework/commerce/types/customer/card.ts index a8731411f..e9b220dcc 100644 --- a/framework/commerce/types/customer/card.ts +++ b/framework/commerce/types/customer/card.ts @@ -1,30 +1,30 @@ export interface Card { - id: string; - mask: string; - provider: string; + id: string + mask: string + provider: string } export interface CardFields { - cardHolder: string; - cardNumber: string; - cardExpireDate: string; - cardCvc: string; - firstName: string; - lastName: string; - company: string; - streetNumber: string; - zipCode: string; - city: string; - country: string; + cardHolder: string + cardNumber: string + cardExpireDate: string + cardCvc: string + firstName: string + lastName: string + company: string + streetNumber: string + zipCode: string + city: string + country: string } export type CustomerCardTypes = { - card?: Card; - fields: CardFields; + card?: Card + fields: CardFields } export type GetCardsHook = { - data: T['card'] | null + data: T['card'][] | null input: {} fetcherInput: { cartId?: string } swrState: { isEmpty: boolean } @@ -48,26 +48,29 @@ export type UpdateItemHook = { export type RemoveItemHook = { data: T['card'] | null - input: { item?: T['fields'] } + input: { item?: T['card'] } fetcherInput: { itemId: string } body: { itemId: string } actionInput: { id: string } } -export type CustomerCardHooks = { - getCards: GetCardsHook - addItem: AddItemHook - updateItem: UpdateItemHook - removeItem: RemoveItemHook -} +export type CustomerCardHooks = + { + getCards: GetCardsHook + addItem: AddItemHook + updateItem: UpdateItemHook + removeItem: RemoveItemHook + } -export type CardsHandler = GetCardsHook & { - body: { cartId?: string } -} +export type CardsHandler = + GetCardsHook & { + body: { cartId?: string } + } -export type AddItemHandler = AddItemHook & { - body: { cartId: string } -} +export type AddItemHandler = + AddItemHook & { + body: { cartId: string } + } export type UpdateItemHandler = UpdateItemHook & { @@ -80,15 +83,18 @@ export type RemoveItemHandler = body: { cartId: string } } - -export type CustomerCardHandlers = { +export type CustomerCardHandlers< + T extends CustomerCardTypes = CustomerCardTypes +> = { getCards: GetCardsHook addItem: AddItemHandler updateItem: UpdateItemHandler removeItem: RemoveItemHandler } -export type CustomerCardSchema = { +export type CustomerCardSchema< + T extends CustomerCardTypes = CustomerCardTypes +> = { endpoint: { options: {} handlers: CustomerCardHandlers diff --git a/framework/ordercloud/customer/address/use-add-item.tsx b/framework/ordercloud/customer/address/use-add-item.tsx index d8234a0ac..cf3f22c46 100644 --- a/framework/ordercloud/customer/address/use-add-item.tsx +++ b/framework/ordercloud/customer/address/use-add-item.tsx @@ -2,7 +2,6 @@ import type { AddItemHook } from '@commerce/types/customer/address' import type { MutationHook } from '@commerce/utils/types' import { useCallback } from 'react' -import { CommerceError } from '@commerce/utils/errors' import useAddItem, { UseAddItem } from '@commerce/customer/address/use-add-item' import useAddresses from './use-addresses' @@ -14,15 +13,6 @@ export const handler: MutationHook = { method: 'POST', }, async fetcher({ input: item, options, fetch }) { - if ( - item.quantity && - (!Number.isInteger(item.quantity) || item.quantity! < 1) - ) { - throw new CommerceError({ - message: 'The item quantity has to be a valid integer greater than 0', - }) - } - const data = await fetch({ ...options, body: { item }, @@ -38,7 +28,7 @@ export const handler: MutationHook = { async function addItem(input) { const data = await fetch({ input }) - await mutate(data, false) + await mutate([data], false) return data }, diff --git a/framework/ordercloud/customer/address/use-addresses.tsx b/framework/ordercloud/customer/address/use-addresses.tsx index dc17c9f00..e9ddc7001 100644 --- a/framework/ordercloud/customer/address/use-addresses.tsx +++ b/framework/ordercloud/customer/address/use-addresses.tsx @@ -2,7 +2,9 @@ import type { GetAddressesHook } from '@commerce/types/customer/address' import { useMemo } from 'react' import { SWRHook } from '@commerce/utils/types' -import useAddresses, { UseAddresses } from '@commerce/customer/address/use-addresses' +import useAddresses, { + UseAddresses, +} from '@commerce/customer/address/use-addresses' export default useAddresses as UseAddresses @@ -22,7 +24,7 @@ export const handler: SWRHook = { Object.create(response, { isEmpty: { get() { - return (response.data?.lineItems?.length ?? 0) <= 0 + return (response.data?.length ?? 0) <= 0 }, enumerable: true, }, diff --git a/framework/ordercloud/customer/address/use-remove-item.tsx b/framework/ordercloud/customer/address/use-remove-item.tsx index b818497a8..4e6282c99 100644 --- a/framework/ordercloud/customer/address/use-remove-item.tsx +++ b/framework/ordercloud/customer/address/use-remove-item.tsx @@ -2,20 +2,22 @@ import type { MutationHookContext, HookFetcherContext, } from '@commerce/utils/types' -import type { Cart, LineItem, RemoveItemHook } from '@commerce/types/cart' +import type { Address, RemoveItemHook } from '@commerce/types/customer/address' import { useCallback } from 'react' import { ValidationError } from '@commerce/utils/errors' -import useRemoveItem, { UseRemoveItem } from '@commerce/customer/address/use-remove-item' +import useRemoveItem, { + UseRemoveItem, +} from '@commerce/customer/address/use-remove-item' import useAddresses from './use-addresses' -export type RemoveItemFn = T extends LineItem - ? (input?: RemoveItemActionInput) => Promise - : (input: RemoveItemActionInput) => Promise +export type RemoveItemFn = T extends Address + ? (input?: RemoveItemActionInput) => Promise
+ : (input: RemoveItemActionInput) => Promise
-export type RemoveItemActionInput = T extends LineItem +export type RemoveItemActionInput = T extends Address ? Partial : RemoveItemHook['actionInput'] @@ -34,12 +36,12 @@ export const handler = { return await fetch({ ...options, body: { itemId } }) }, useHook: ({ fetch }: MutationHookContext) => - function useHook( + function useHook( ctx: { item?: T } = {} ) { const { item } = ctx const { mutate } = useAddresses() - const removeItem: RemoveItemFn = async (input) => { + const removeItem: RemoveItemFn
= async (input) => { const itemId = input?.id ?? item?.id if (!itemId) { @@ -50,7 +52,7 @@ export const handler = { const data = await fetch({ input: { itemId } }) - await mutate(data, false) + await mutate([], false) return data } diff --git a/framework/ordercloud/customer/address/use-update-item.tsx b/framework/ordercloud/customer/address/use-update-item.tsx index 8bd0c98e4..720a339d8 100644 --- a/framework/ordercloud/customer/address/use-update-item.tsx +++ b/framework/ordercloud/customer/address/use-update-item.tsx @@ -2,19 +2,18 @@ import type { HookFetcherContext, MutationHookContext, } from '@commerce/utils/types' -import type { UpdateItemHook, LineItem } from '@commerce/types/cart' +import type { UpdateItemHook, Address } from '@commerce/types/customer/address' import { useCallback } from 'react' -import debounce from 'lodash.debounce' import { MutationHook } from '@commerce/utils/types' -import { ValidationError } from '@commerce/utils/errors' -import useUpdateItem, { UseUpdateItem } from '@commerce/customer/address/use-update-item' +import useUpdateItem, { + UseUpdateItem, +} from '@commerce/customer/address/use-update-item' -import { handler as removeItemHandler } from './use-remove-item' import useAddresses from './use-addresses' -export type UpdateItemActionInput = T extends LineItem +export type UpdateItemActionInput = T extends Address ? Partial : UpdateItemHook['actionInput'] @@ -30,63 +29,23 @@ export const handler: MutationHook = { options, fetch, }: HookFetcherContext) { - if (Number.isInteger(item.quantity)) { - // Also allow the update hook to remove an item if the quantity is lower than 1 - if (item.quantity! < 1) { - return removeItemHandler.fetcher({ - options: removeItemHandler.fetchOptions, - input: { itemId }, - fetch, - }) - } - } else if (item.quantity) { - throw new ValidationError({ - message: 'The item quantity has to be a valid integer', - }) - } - return await fetch({ ...options, body: { itemId, item }, }) }, useHook: ({ fetch }: MutationHookContext) => - function useHook( - ctx: { - item?: T - wait?: number - } = {} - ) { - const { item } = ctx - const { mutate } = useAddresses() as any + function useHook() { + const { mutate } = useAddresses() return useCallback( - debounce(async (input: UpdateItemActionInput) => { - const itemId = input.id ?? item?.id - const productId = input.productId ?? item?.productId - const variantId = input.productId ?? item?.variantId + async function updateItem(input) { + const data = await fetch({ input }) - if (!itemId || !productId) { - throw new ValidationError({ - message: 'Invalid input used for this operation', - }) - } - - const data = await fetch({ - input: { - itemId, - item: { - productId, - variantId: variantId || '', - quantity: input.quantity, - }, - }, - }) - - await mutate(data, false) + await mutate([], false) return data - }, ctx.wait ?? 500), + }, [fetch, mutate] ) }, diff --git a/framework/ordercloud/customer/card/use-add-item.tsx b/framework/ordercloud/customer/card/use-add-item.tsx index 466ce8b5b..6c6a6d7fd 100644 --- a/framework/ordercloud/customer/card/use-add-item.tsx +++ b/framework/ordercloud/customer/card/use-add-item.tsx @@ -2,7 +2,6 @@ import type { AddItemHook } from '@commerce/types/customer/card' import type { MutationHook } from '@commerce/utils/types' import { useCallback } from 'react' -import { CommerceError } from '@commerce/utils/errors' import useAddItem, { UseAddItem } from '@commerce/customer/card/use-add-item' import useCards from './use-cards' @@ -14,15 +13,6 @@ export const handler: MutationHook = { method: 'POST', }, async fetcher({ input: item, options, fetch }) { - if ( - item.quantity && - (!Number.isInteger(item.quantity) || item.quantity! < 1) - ) { - throw new CommerceError({ - message: 'The item quantity has to be a valid integer greater than 0', - }) - } - const data = await fetch({ ...options, body: { item }, @@ -38,7 +28,7 @@ export const handler: MutationHook = { async function addItem(input) { const data = await fetch({ input }) - await mutate(data, false) + await mutate([data], false) return data }, diff --git a/framework/ordercloud/customer/card/use-cards.tsx b/framework/ordercloud/customer/card/use-cards.tsx index 76f030462..92236deb2 100644 --- a/framework/ordercloud/customer/card/use-cards.tsx +++ b/framework/ordercloud/customer/card/use-cards.tsx @@ -22,7 +22,7 @@ export const handler: SWRHook = { Object.create(response, { isEmpty: { get() { - return (response.data?.lineItems?.length ?? 0) <= 0 + return (response.data?.length ?? 0) <= 0 }, enumerable: true, }, diff --git a/framework/ordercloud/customer/card/use-remove-item.tsx b/framework/ordercloud/customer/card/use-remove-item.tsx index cf46404db..dc0781b95 100644 --- a/framework/ordercloud/customer/card/use-remove-item.tsx +++ b/framework/ordercloud/customer/card/use-remove-item.tsx @@ -2,20 +2,22 @@ import type { MutationHookContext, HookFetcherContext, } from '@commerce/utils/types' -import type { Cart, LineItem, RemoveItemHook } from '@commerce/types/customer/card' +import type { Card, RemoveItemHook } from '@commerce/types/customer/card' import { useCallback } from 'react' import { ValidationError } from '@commerce/utils/errors' -import useRemoveItem, { UseRemoveItem } from '@commerce/customer/card/use-remove-item' +import useRemoveItem, { + UseRemoveItem, +} from '@commerce/customer/card/use-remove-item' import useCards from './use-cards' -export type RemoveItemFn = T extends LineItem - ? (input?: RemoveItemActionInput) => Promise - : (input: RemoveItemActionInput) => Promise +export type RemoveItemFn = T extends Card + ? (input?: RemoveItemActionInput) => Promise + : (input: RemoveItemActionInput) => Promise -export type RemoveItemActionInput = T extends LineItem +export type RemoveItemActionInput = T extends Card ? Partial : RemoveItemHook['actionInput'] @@ -34,12 +36,12 @@ export const handler = { return await fetch({ ...options, body: { itemId } }) }, useHook: ({ fetch }: MutationHookContext) => - function useHook( + function useHook( ctx: { item?: T } = {} ) { const { item } = ctx const { mutate } = useCards() - const removeItem: RemoveItemFn = async (input) => { + const removeItem: RemoveItemFn = async (input) => { const itemId = input?.id ?? item?.id if (!itemId) { @@ -50,7 +52,7 @@ export const handler = { const data = await fetch({ input: { itemId } }) - await mutate(data, false) + await mutate([], false) return data } diff --git a/framework/ordercloud/customer/card/use-update-item.tsx b/framework/ordercloud/customer/card/use-update-item.tsx index 88d59aa78..0dfb218d5 100644 --- a/framework/ordercloud/customer/card/use-update-item.tsx +++ b/framework/ordercloud/customer/card/use-update-item.tsx @@ -2,19 +2,18 @@ import type { HookFetcherContext, MutationHookContext, } from '@commerce/utils/types' -import type { UpdateItemHook, LineItem } from '@commerce/types/customer/card' +import type { UpdateItemHook, Card } from '@commerce/types/customer/card' import { useCallback } from 'react' -import debounce from 'lodash.debounce' import { MutationHook } from '@commerce/utils/types' -import { ValidationError } from '@commerce/utils/errors' -import useUpdateItem, { UseUpdateItem } from '@commerce/customer/card/use-update-item' +import useUpdateItem, { + UseUpdateItem, +} from '@commerce/customer/card/use-update-item' -import { handler as removeItemHandler } from './use-remove-item' import useCards from './use-cards' -export type UpdateItemActionInput = T extends LineItem +export type UpdateItemActionInput = T extends Card ? Partial : UpdateItemHook['actionInput'] @@ -30,63 +29,23 @@ export const handler: MutationHook = { options, fetch, }: HookFetcherContext) { - if (Number.isInteger(item.quantity)) { - // Also allow the update hook to remove an item if the quantity is lower than 1 - if (item.quantity! < 1) { - return removeItemHandler.fetcher({ - options: removeItemHandler.fetchOptions, - input: { itemId }, - fetch, - }) - } - } else if (item.quantity) { - throw new ValidationError({ - message: 'The item quantity has to be a valid integer', - }) - } - return await fetch({ ...options, body: { itemId, item }, }) }, useHook: ({ fetch }: MutationHookContext) => - function useHook( - ctx: { - item?: T - wait?: number - } = {} - ) { - const { item } = ctx - const { mutate } = useCards() as any + function useHook() { + const { mutate } = useCards() return useCallback( - debounce(async (input: UpdateItemActionInput) => { - const itemId = input.id ?? item?.id - const productId = input.productId ?? item?.productId - const variantId = input.productId ?? item?.variantId + async function updateItem(input) { + const data = await fetch({ input }) - if (!itemId || !productId) { - throw new ValidationError({ - message: 'Invalid input used for this operation', - }) - } - - const data = await fetch({ - input: { - itemId, - item: { - productId, - variantId: variantId || '', - quantity: input.quantity, - }, - }, - }) - - await mutate(data, false) + await mutate([], false) return data - }, ctx.wait ?? 500), + }, [fetch, mutate] ) },