forked from crowetic/commerce
Improved types for operations
This commit is contained in:
parent
172b413521
commit
e5f0809070
@ -1,14 +1,15 @@
|
||||
import { useCallback } from 'react'
|
||||
import debounce from 'lodash.debounce'
|
||||
import type { HookFetcher } from '@commerce/utils/types'
|
||||
import { CommerceError } from '@commerce/utils/errors'
|
||||
import { ValidationError } from '@commerce/utils/errors'
|
||||
import useCartUpdateItem from '@commerce/cart/use-update-item'
|
||||
import { normalizeCart } from '../lib/normalize'
|
||||
import type {
|
||||
Cart,
|
||||
BigcommerceCart,
|
||||
UpdateCartItemBody,
|
||||
UpdateCartItemInput,
|
||||
Cart,
|
||||
BigcommerceCart,
|
||||
LineItem,
|
||||
} from '../types'
|
||||
import { fetcher as removeFetcher } from './use-remove-item'
|
||||
import useCart from './use-cart'
|
||||
@ -29,12 +30,12 @@ export const fetcher: HookFetcher<Cart | null, UpdateCartItemBody> = async (
|
||||
return removeFetcher(null, { itemId }, fetch)
|
||||
}
|
||||
} else if (item.quantity) {
|
||||
throw new CommerceError({
|
||||
throw new ValidationError({
|
||||
message: 'The item quantity has to be a valid integer',
|
||||
})
|
||||
}
|
||||
|
||||
const data = await fetch<BigcommerceCart>({
|
||||
const data = await fetch<BigcommerceCart, UpdateCartItemBody>({
|
||||
...defaultOpts,
|
||||
...options,
|
||||
body: { itemId, item },
|
||||
@ -44,7 +45,9 @@ export const fetcher: HookFetcher<Cart | null, UpdateCartItemBody> = async (
|
||||
}
|
||||
|
||||
function extendHook(customFetcher: typeof fetcher, cfg?: { wait?: number }) {
|
||||
const useUpdateItem = (item?: any) => {
|
||||
const useUpdateItem = <T extends LineItem | undefined = undefined>(
|
||||
item?: T
|
||||
) => {
|
||||
const { mutate } = useCart()
|
||||
const fn = useCartUpdateItem<Cart | null, UpdateCartItemBody>(
|
||||
defaultOpts,
|
||||
@ -52,26 +55,31 @@ function extendHook(customFetcher: typeof fetcher, cfg?: { wait?: number }) {
|
||||
)
|
||||
|
||||
return useCallback(
|
||||
debounce(async (input: UpdateCartItemInput) => {
|
||||
console.log('INPUT', input, {
|
||||
itemId: input.id ?? item?.id,
|
||||
item: {
|
||||
productId: input.productId ?? item?.product_id,
|
||||
variantId: input.productId ?? item?.variant_id,
|
||||
quantity: input.quantity,
|
||||
},
|
||||
})
|
||||
const data = await fn({
|
||||
itemId: input.id ?? item?.id,
|
||||
item: {
|
||||
productId: input.productId ?? item?.product_id,
|
||||
variantId: input.productId ?? item?.variant_id,
|
||||
quantity: input.quantity,
|
||||
},
|
||||
})
|
||||
await mutate(data, false)
|
||||
return data
|
||||
}, cfg?.wait ?? 500),
|
||||
debounce(
|
||||
async (
|
||||
input: T extends LineItem
|
||||
? Partial<UpdateCartItemInput>
|
||||
: UpdateCartItemInput
|
||||
) => {
|
||||
const itemId = input.id ?? item?.id
|
||||
const productId = input.productId ?? item?.productId
|
||||
const variantId = input.productId ?? item?.variantId
|
||||
|
||||
if (!itemId || !productId || !variantId) {
|
||||
throw new ValidationError({
|
||||
message: 'Invalid input used for this operation',
|
||||
})
|
||||
}
|
||||
|
||||
const data = await fn({
|
||||
itemId,
|
||||
item: { productId, variantId, quantity: input.quantity },
|
||||
})
|
||||
await mutate(data, false)
|
||||
return data
|
||||
},
|
||||
cfg?.wait ?? 500
|
||||
),
|
||||
[fn, mutate]
|
||||
)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import type { Cart as BigcommerceCart } from '../api/cart'
|
||||
import type { Cart, BigcommerceCart, LineItem } from '../types'
|
||||
import update from './immutability'
|
||||
|
||||
function normalizeProductOption(productOption: any) {
|
||||
@ -90,6 +90,7 @@ function normalizeLineItem(item: any): LineItem {
|
||||
return {
|
||||
id: item.id,
|
||||
variantId: String(item.variant_id),
|
||||
productId: String(item.product_id),
|
||||
name: item.name,
|
||||
quantity: item.quantity,
|
||||
variant: {
|
||||
|
@ -39,6 +39,7 @@ export type OptionSelections = {
|
||||
}
|
||||
|
||||
export interface CartItemBody extends Core.CartItemBody {
|
||||
productId: string // The product id is always required for BC
|
||||
optionSelections?: OptionSelections
|
||||
}
|
||||
|
||||
@ -46,7 +47,8 @@ export interface UpdateCartItemBody extends Core.UpdateCartItemBody {
|
||||
item: CartItemBody
|
||||
}
|
||||
|
||||
export interface UpdateCartItemInput extends Core.UpdateCartItemInput {}
|
||||
export interface UpdateCartItemInput
|
||||
extends Core.UpdateCartItemInput<CartItemBody> {}
|
||||
|
||||
export interface UpdateCartItemHandlerBody
|
||||
extends Core.UpdateCartItemHandlerBody {}
|
||||
|
@ -6,6 +6,7 @@ export interface Discount {
|
||||
export interface LineItem {
|
||||
id: string
|
||||
variantId: string
|
||||
productId: string
|
||||
name: string
|
||||
quantity: number
|
||||
discounts: Discount[]
|
||||
@ -88,8 +89,8 @@ export interface Cart {
|
||||
|
||||
// Base cart item body used for cart mutations
|
||||
export interface CartItemBody {
|
||||
productId: string
|
||||
variantId: string
|
||||
productId?: string
|
||||
quantity?: number
|
||||
}
|
||||
|
||||
@ -100,8 +101,8 @@ export interface UpdateCartItemBody {
|
||||
}
|
||||
|
||||
// Input expected by the `useUpdateItem` hook
|
||||
export interface UpdateCartItemInput extends Partial<CartItemBody> {
|
||||
id?: string
|
||||
export type UpdateCartItemInput<T extends CartItemBody> = T & {
|
||||
id: string
|
||||
}
|
||||
|
||||
// Body expected by the update operation handler
|
||||
|
@ -26,6 +26,14 @@ export class CommerceError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// Used for errors that come from a bad implementation of the hooks
|
||||
export class ValidationError extends CommerceError {
|
||||
constructor(options: ErrorProps) {
|
||||
super(options)
|
||||
this.code = 'validation_error'
|
||||
}
|
||||
}
|
||||
|
||||
export class FetcherError extends CommerceError {
|
||||
status: number
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
// Core fetcher added by CommerceProvider
|
||||
export type Fetcher<T> = (options: FetcherOptions) => T | Promise<T>
|
||||
|
||||
export type FetcherOptions = {
|
||||
export type FetcherOptions<Body = any> = {
|
||||
url?: string
|
||||
query?: string
|
||||
method?: string
|
||||
variables?: any
|
||||
body?: any
|
||||
body?: Body
|
||||
}
|
||||
|
||||
export type HookFetcher<Data, Input = null, Result = any> = (
|
||||
options: HookFetcherOptions | null,
|
||||
input: Input,
|
||||
fetch: <T = Result>(options: FetcherOptions) => Promise<T>
|
||||
fetch: <T = Result, Body = any>(options: FetcherOptions<Body>) => Promise<T>
|
||||
) => Data | Promise<Data>
|
||||
|
||||
export type HookFetcherOptions = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user