From e5f0809070b28126da1e36b1b7031f44d4d8b59a Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Fri, 29 Jan 2021 19:24:10 -0500 Subject: [PATCH] Improved types for operations --- .../bigcommerce/cart/use-update-item.tsx | 60 +++++++++++-------- framework/bigcommerce/lib/normalize.ts | 3 +- framework/bigcommerce/types.ts | 4 +- framework/commerce/types.ts | 7 ++- framework/commerce/utils/errors.ts | 8 +++ framework/commerce/utils/types.ts | 6 +- 6 files changed, 54 insertions(+), 34 deletions(-) diff --git a/framework/bigcommerce/cart/use-update-item.tsx b/framework/bigcommerce/cart/use-update-item.tsx index b3a3e0566..6592b090f 100644 --- a/framework/bigcommerce/cart/use-update-item.tsx +++ b/framework/bigcommerce/cart/use-update-item.tsx @@ -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 = 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({ + const data = await fetch({ ...defaultOpts, ...options, body: { itemId, item }, @@ -44,7 +45,9 @@ export const fetcher: HookFetcher = async ( } function extendHook(customFetcher: typeof fetcher, cfg?: { wait?: number }) { - const useUpdateItem = (item?: any) => { + const useUpdateItem = ( + item?: T + ) => { const { mutate } = useCart() const fn = useCartUpdateItem( 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 + ) => { + 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] ) } diff --git a/framework/bigcommerce/lib/normalize.ts b/framework/bigcommerce/lib/normalize.ts index ec0f73a86..89aed2c38 100644 --- a/framework/bigcommerce/lib/normalize.ts +++ b/framework/bigcommerce/lib/normalize.ts @@ -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: { diff --git a/framework/bigcommerce/types.ts b/framework/bigcommerce/types.ts index d9b81acea..766f2dbe9 100644 --- a/framework/bigcommerce/types.ts +++ b/framework/bigcommerce/types.ts @@ -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 {} export interface UpdateCartItemHandlerBody extends Core.UpdateCartItemHandlerBody {} diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts index 8ffbf5421..c662077a1 100644 --- a/framework/commerce/types.ts +++ b/framework/commerce/types.ts @@ -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 { - id?: string +export type UpdateCartItemInput = T & { + id: string } // Body expected by the update operation handler diff --git a/framework/commerce/utils/errors.ts b/framework/commerce/utils/errors.ts index 76f899ab7..f4ab9fb9a 100644 --- a/framework/commerce/utils/errors.ts +++ b/framework/commerce/utils/errors.ts @@ -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 diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts index 483b0c73c..010205f62 100644 --- a/framework/commerce/utils/types.ts +++ b/framework/commerce/utils/types.ts @@ -1,18 +1,18 @@ // Core fetcher added by CommerceProvider export type Fetcher = (options: FetcherOptions) => T | Promise -export type FetcherOptions = { +export type FetcherOptions = { url?: string query?: string method?: string variables?: any - body?: any + body?: Body } export type HookFetcher = ( options: HookFetcherOptions | null, input: Input, - fetch: (options: FetcherOptions) => Promise + fetch: (options: FetcherOptions) => Promise ) => Data | Promise export type HookFetcherOptions = {