From d9243880a3c81c65defa7f4699033cb0ed0c7439 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Sun, 14 Feb 2021 18:40:48 -0500 Subject: [PATCH 1/9] Fixed some types --- components/cart/CartItem/CartItem.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/components/cart/CartItem/CartItem.tsx b/components/cart/CartItem/CartItem.tsx index 87fb86d0b..bb57c3f25 100644 --- a/components/cart/CartItem/CartItem.tsx +++ b/components/cart/CartItem/CartItem.tsx @@ -75,6 +75,8 @@ const CartItem = ({ setRemoving(false) } } + // TODO: Add a type for this + const options = (item as any).options useEffect(() => { // Reset the quantity state if the item quantity changes @@ -95,8 +97,8 @@ const CartItem = ({ className={s.productImage} width={150} height={150} - src={item.variant.image.url} - alt={item.variant.image.altText} + src={item.variant.image!.url} + alt={item.variant.image!.altText} unoptimized /> @@ -109,15 +111,15 @@ const CartItem = ({ {item.name} - {item.options && item.options.length > 0 ? ( + {options && options.length > 0 ? (
- {item.options.map((option: ItemOption, i: number) => ( + {options.map((option: ItemOption, i: number) => ( {option.value} - {i === item.options.length - 1 ? '' : ', '} + {i === options.length - 1 ? '' : ', '} ))}
From c636fcbc4be2a364bb09c1e78b1218114d52dc82 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 00:09:57 -0500 Subject: [PATCH 2/9] Fixed more types --- components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx | 3 ++- components/product/ProductCard/ProductCard.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx index d55f51f7a..2e01fa0cb 100644 --- a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx +++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx @@ -8,7 +8,8 @@ import { getCategoryPath, getDesignerPath } from '@lib/search' interface Props { categories?: any brands?: any - products?: Product[] + // TODO: use the product type here + products?: any[] } const Head: FC = ({ categories, brands, products = [] }) => { diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 464f097e8..461524855 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -7,7 +7,8 @@ import Image, { ImageProps } from 'next/image' interface Props { className?: string - product: Product + // TODO: use the product type here + product: any variant?: 'slim' | 'simple' imgProps?: Omit } From 62ed50a64641e1476b088ef69227cf62e3a4485b Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 10:15:20 -0500 Subject: [PATCH 3/9] Fixed product types --- .../HomeAllProductsGrid.tsx | 4 +- .../product/ProductCard/ProductCard.tsx | 4 +- .../product/ProductView/ProductView.tsx | 3 +- components/product/helpers.ts | 2 + .../WishlistButton/WishlistButton.tsx | 1 + .../wishlist/WishlistCard/WishlistCard.tsx | 5 +- .../api/catalog/handlers/get-products.ts | 2 +- framework/bigcommerce/api/catalog/products.ts | 2 +- framework/bigcommerce/api/wishlist/index.ts | 3 +- framework/bigcommerce/lib/normalize.ts | 1 + .../bigcommerce/product/get-all-products.ts | 2 + framework/commerce/types.d.ts | 75 ------------------- framework/commerce/types.ts | 51 +++++++++++++ 13 files changed, 70 insertions(+), 85 deletions(-) delete mode 100644 framework/commerce/types.d.ts diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx index 2e01fa0cb..49e115df6 100644 --- a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx +++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx @@ -1,5 +1,6 @@ import { FC } from 'react' import Link from 'next/link' +import type { Product } from '@commerce/types' import { Grid } from '@components/ui' import { ProductCard } from '@components/product' import s from './HomeAllProductsGrid.module.css' @@ -8,8 +9,7 @@ import { getCategoryPath, getDesignerPath } from '@lib/search' interface Props { categories?: any brands?: any - // TODO: use the product type here - products?: any[] + products?: Product[] } const Head: FC = ({ categories, brands, products = [] }) => { diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx index 461524855..a3bd73576 100644 --- a/components/product/ProductCard/ProductCard.tsx +++ b/components/product/ProductCard/ProductCard.tsx @@ -1,14 +1,14 @@ import { FC } from 'react' import cn from 'classnames' import Link from 'next/link' +import type { Product } from '@commerce/types' import s from './ProductCard.module.css' import Image, { ImageProps } from 'next/image' // import WishlistButton from '@components/wishlist/WishlistButton' interface Props { className?: string - // TODO: use the product type here - product: any + product: Product variant?: 'slim' | 'simple' imgProps?: Omit } diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 65fa4d93f..b5452bef1 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -8,6 +8,7 @@ import { useUI } from '@components/ui' import { Swatch, ProductSlider } from '@components/product' import { Button, Container, Text } from '@components/ui' +import type { Product } from '@commerce/types' import usePrice from '@framework/product/use-price' import { useAddItem } from '@framework/cart' @@ -41,7 +42,7 @@ const ProductView: FC = ({ product }) => { setLoading(true) try { await addItem({ - productId: product.id, + productId: String(product.id), variantId: variant ? variant.id : product.variants[0].id, }) openSidebar() diff --git a/components/product/helpers.ts b/components/product/helpers.ts index ae0c43530..029476c92 100644 --- a/components/product/helpers.ts +++ b/components/product/helpers.ts @@ -1,3 +1,5 @@ +import type { Product } from '@commerce/types' + export type SelectedOptions = { size: string | null color: string | null diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx index dced18a89..0c4c20194 100644 --- a/components/wishlist/WishlistButton/WishlistButton.tsx +++ b/components/wishlist/WishlistButton/WishlistButton.tsx @@ -3,6 +3,7 @@ import cn from 'classnames' import { Heart } from '@components/icons' import { useUI } from '@components/ui' +import type { Product, ProductVariant } from '@commerce/types' import useCustomer from '@framework/customer/use-customer' import useAddItem from '@framework/wishlist/use-add-item' import useRemoveItem from '@framework/wishlist/use-remove-item' diff --git a/components/wishlist/WishlistCard/WishlistCard.tsx b/components/wishlist/WishlistCard/WishlistCard.tsx index d1a9403b3..38663ab68 100644 --- a/components/wishlist/WishlistCard/WishlistCard.tsx +++ b/components/wishlist/WishlistCard/WishlistCard.tsx @@ -7,6 +7,7 @@ import { Trash } from '@components/icons' import { Button, Text } from '@components/ui' import { useUI } from '@components/ui/context' +import type { Product } from '@commerce/types' import usePrice from '@framework/product/use-price' import useAddItem from '@framework/cart/use-add-item' import useRemoveItem from '@framework/wishlist/use-remove-item' @@ -42,8 +43,8 @@ const WishlistCard: FC = ({ product }) => { setLoading(true) try { await addItem({ - productId: product.id, - variantId: product.variants[0].id, + productId: String(product.id), + variantId: String(product.variants[0].id), }) openSidebar() setLoading(false) diff --git a/framework/bigcommerce/api/catalog/handlers/get-products.ts b/framework/bigcommerce/api/catalog/handlers/get-products.ts index 894dc5cf3..20b9c5254 100644 --- a/framework/bigcommerce/api/catalog/handlers/get-products.ts +++ b/framework/bigcommerce/api/catalog/handlers/get-products.ts @@ -1,4 +1,4 @@ -import { Product } from 'framework/types' +import { Product } from '@commerce/types' import getAllProducts, { ProductEdge } from '../../../product/get-all-products' import type { ProductsHandlers } from '../products' diff --git a/framework/bigcommerce/api/catalog/products.ts b/framework/bigcommerce/api/catalog/products.ts index d13dcd3c3..d52b2de7e 100644 --- a/framework/bigcommerce/api/catalog/products.ts +++ b/framework/bigcommerce/api/catalog/products.ts @@ -1,3 +1,4 @@ +import type { Product } from '@commerce/types' import isAllowedMethod from '../utils/is-allowed-method' import createApiHandler, { BigcommerceApiHandler, @@ -5,7 +6,6 @@ import createApiHandler, { } from '../utils/create-api-handler' import { BigcommerceApiError } from '../utils/errors' import getProducts from './handlers/get-products' -import { Product } from 'framework/types' export type SearchProductsData = { products: Product[] diff --git a/framework/bigcommerce/api/wishlist/index.ts b/framework/bigcommerce/api/wishlist/index.ts index e892d2e78..7c700689c 100644 --- a/framework/bigcommerce/api/wishlist/index.ts +++ b/framework/bigcommerce/api/wishlist/index.ts @@ -11,6 +11,7 @@ import type { import getWishlist from './handlers/get-wishlist' import addItem from './handlers/add-item' import removeItem from './handlers/remove-item' +import type { Product, ProductVariant, Customer } from '@commerce/types' export type { Wishlist, WishlistItem } @@ -24,7 +25,7 @@ export type AddItemBody = { item: ItemBody } export type RemoveItemBody = { itemId: Product['id'] } export type WishlistBody = { - customer_id: Customer['id'] + customer_id: Customer['entityId'] is_public: number name: string items: any[] diff --git a/framework/bigcommerce/lib/normalize.ts b/framework/bigcommerce/lib/normalize.ts index 89aed2c38..cc7606099 100644 --- a/framework/bigcommerce/lib/normalize.ts +++ b/framework/bigcommerce/lib/normalize.ts @@ -1,3 +1,4 @@ +import type { Product } from '@commerce/types' import type { Cart, BigcommerceCart, LineItem } from '../types' import update from './immutability' diff --git a/framework/bigcommerce/product/get-all-products.ts b/framework/bigcommerce/product/get-all-products.ts index b7d728c4a..4c563bc62 100644 --- a/framework/bigcommerce/product/get-all-products.ts +++ b/framework/bigcommerce/product/get-all-products.ts @@ -2,6 +2,7 @@ import type { GetAllProductsQuery, GetAllProductsQueryVariables, } from '../schema' +import type { Product } from '@commerce/types' import type { RecursivePartial, RecursiveRequired } from '../api/utils/types' import filterEdges from '../api/utils/filter-edges' import setProductLocaleMeta from '../api/utils/set-product-locale-meta' @@ -94,6 +95,7 @@ async function getAllProducts({ variables?: ProductVariables config?: BigcommerceConfig preview?: boolean + // TODO: fix the product type here } = {}): Promise<{ products: Product[] | any[] }> { config = getConfig(config) diff --git a/framework/commerce/types.d.ts b/framework/commerce/types.d.ts deleted file mode 100644 index 9e69ec25d..000000000 --- a/framework/commerce/types.d.ts +++ /dev/null @@ -1,75 +0,0 @@ -interface Entity { - id: string | number - [prop: string]: any -} - -interface Product extends Entity { - name: string - description: string - slug?: string - path?: string - images: ProductImage[] - variants: ProductVariant[] - price: ProductPrice - options: ProductOption[] - sku?: string -} - -interface ProductOption extends Entity { - displayName: string - values: ProductOptionValues[] -} - -interface ProductOptionValues { - label: string - hexColors?: string[] -} - -interface ProductImage { - url: string - alt?: string -} - -interface ProductVariant { - id: string | number - options: ProductOption[] -} - -interface ProductPrice { - value: number - currencyCode: 'USD' | 'ARS' | string | undefined - retailPrice?: number - salePrice?: number - listPrice?: number - extendedSalePrice?: number - extendedListPrice?: number -} - -interface CartItem extends Entity { - quantity: number - productId: Product['id'] - variantId: ProductVariant['id'] - images: ProductImage[] -} - -interface Wishlist extends Entity { - products: Pick[] -} - -interface Order {} - -interface Customer extends Entity {} - -type UseCustomerResponse = { - customer: Customer -} | null - -interface Category extends Entity { - name: string -} - -interface Brand extends Entity { - name: string -} - -type Features = 'wishlist' | 'customer' diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts index 41aedb228..1f8390535 100644 --- a/framework/commerce/types.ts +++ b/framework/commerce/types.ts @@ -148,3 +148,54 @@ export interface RemoveCartItemBody { export interface RemoveCartItemHandlerBody extends Partial { cartId?: string } + +/** + * Temporal types + */ + +interface Entity { + id: string | number + [prop: string]: any +} + +export interface Product extends Entity { + name: string + description: string + slug?: string + path?: string + images: ProductImage[] + variants: ProductVariant2[] + price: ProductPrice + options: ProductOption[] + sku?: string +} + +interface ProductOption extends Entity { + displayName: string + values: ProductOptionValues[] +} + +interface ProductOptionValues { + label: string + hexColors?: string[] +} + +interface ProductImage { + url: string + alt?: string +} + +interface ProductVariant2 { + id: string | number + options: ProductOption[] +} + +interface ProductPrice { + value: number + currencyCode: 'USD' | 'ARS' | string | undefined + retailPrice?: number + salePrice?: number + listPrice?: number + extendedSalePrice?: number + extendedListPrice?: number +} From c62187425053b6d347a76b40ce0a0ccba9019e11 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 10:25:35 -0500 Subject: [PATCH 4/9] Fixed another product type --- components/product/ProductView/ProductView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index b5452bef1..61beda7fe 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -43,7 +43,7 @@ const ProductView: FC = ({ product }) => { try { await addItem({ productId: String(product.id), - variantId: variant ? variant.id : product.variants[0].id, + variantId: String(variant ? variant.id : product.variants[0].id), }) openSidebar() setLoading(false) From 499516e967833749518a03d5ef6fe9448c30de31 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 10:41:57 -0500 Subject: [PATCH 5/9] Updated type --- framework/bigcommerce/api/catalog/handlers/get-products.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/bigcommerce/api/catalog/handlers/get-products.ts b/framework/bigcommerce/api/catalog/handlers/get-products.ts index 20b9c5254..bedd773b0 100644 --- a/framework/bigcommerce/api/catalog/handlers/get-products.ts +++ b/framework/bigcommerce/api/catalog/handlers/get-products.ts @@ -60,7 +60,7 @@ const getProducts: ProductsHandlers['getProducts'] = async ({ const productsById = graphqlData.products.reduce<{ [k: number]: Product }>((prods, p) => { - prods[p.id] = p + prods[Number(p.id)] = p return prods }, {}) From bb0b8d2771afc8450f86351c6cd481c01a129073 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 12:02:24 -0500 Subject: [PATCH 6/9] Fixed remaining issues with types --- .../customer/get-customer-wishlist.ts | 2 +- framework/bigcommerce/product/get-product.ts | 1 + framework/bigcommerce/provider.tsx | 2 +- framework/bigcommerce/wishlist/use-add-item.tsx | 16 ++++++++++------ .../bigcommerce/wishlist/use-remove-item.tsx | 8 ++++---- framework/commerce/wishlist/use-add-item.tsx | 7 +++++++ pages/product/[slug].tsx | 2 +- pages/wishlist.tsx | 2 +- 8 files changed, 26 insertions(+), 14 deletions(-) diff --git a/framework/bigcommerce/customer/get-customer-wishlist.ts b/framework/bigcommerce/customer/get-customer-wishlist.ts index a3c7413cc..e854ff933 100644 --- a/framework/bigcommerce/customer/get-customer-wishlist.ts +++ b/framework/bigcommerce/customer/get-customer-wishlist.ts @@ -68,7 +68,7 @@ async function getCustomerWishlist({ const productsById = graphqlData.products.reduce<{ [k: number]: ProductEdge }>((prods, p) => { - prods[p.node.entityId] = p + prods[Number(p.node.entityId)] = p as any return prods }, {}) // Populate the wishlist items with the graphql products diff --git a/framework/bigcommerce/product/get-product.ts b/framework/bigcommerce/product/get-product.ts index 3624a9cca..7d77eb194 100644 --- a/framework/bigcommerce/product/get-product.ts +++ b/framework/bigcommerce/product/get-product.ts @@ -3,6 +3,7 @@ import setProductLocaleMeta from '../api/utils/set-product-locale-meta' import { productInfoFragment } from '../api/fragments/product' import { BigcommerceConfig, getConfig } from '../api' import { normalizeProduct } from '@framework/lib/normalize' +import type { Product } from '@commerce/types' export const getProductQuery = /* GraphQL */ ` query getProduct( diff --git a/framework/bigcommerce/provider.tsx b/framework/bigcommerce/provider.tsx index 6fd02e304..e8ac29cf5 100644 --- a/framework/bigcommerce/provider.tsx +++ b/framework/bigcommerce/provider.tsx @@ -107,7 +107,7 @@ const useWishlist: HookHandler< const { data: customer } = useCustomer() const response = useData({ input: [ - ['customerId', customer?.id], + ['customerId', (customer as any)?.id], ['includeProducts', input.includeProducts], ], swrOptions: { diff --git a/framework/bigcommerce/wishlist/use-add-item.tsx b/framework/bigcommerce/wishlist/use-add-item.tsx index 6e7d9de41..eb961951a 100644 --- a/framework/bigcommerce/wishlist/use-add-item.tsx +++ b/framework/bigcommerce/wishlist/use-add-item.tsx @@ -1,19 +1,23 @@ import { useCallback } from 'react' import { HookFetcher } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' -import useWishlistAddItem from '@commerce/wishlist/use-add-item' +import useWishlistAddItem, { + AddItemInput, +} from '@commerce/wishlist/use-add-item' +import { UseWishlistInput } from '@commerce/wishlist/use-wishlist' import type { ItemBody, AddItemBody } from '../api/wishlist' import useCustomer from '../customer/use-customer' -import useWishlist, { UseWishlistOptions, Wishlist } from './use-wishlist' +import useWishlist from './use-wishlist' +import type { BigcommerceProvider } from '..' const defaultOpts = { url: '/api/bigcommerce/wishlist', method: 'POST', } -export type AddItemInput = ItemBody +// export type AddItemInput = ItemBody -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, { item }, fetch @@ -27,13 +31,13 @@ export const fetcher: HookFetcher = ( } export function extendHook(customFetcher: typeof fetcher) { - const useAddItem = (opts?: UseWishlistOptions) => { + const useAddItem = (opts?: UseWishlistInput) => { const { data: customer } = useCustomer() const { revalidate } = useWishlist(opts) const fn = useWishlistAddItem(defaultOpts, customFetcher) return useCallback( - async function addItem(input: AddItemInput) { + async function addItem(input: AddItemInput) { if (!customer) { // A signed customer is required in order to have a wishlist throw new CommerceError({ diff --git a/framework/bigcommerce/wishlist/use-remove-item.tsx b/framework/bigcommerce/wishlist/use-remove-item.tsx index 86614a21a..d00b3e78b 100644 --- a/framework/bigcommerce/wishlist/use-remove-item.tsx +++ b/framework/bigcommerce/wishlist/use-remove-item.tsx @@ -4,7 +4,7 @@ import { CommerceError } from '@commerce/utils/errors' import useWishlistRemoveItem from '@commerce/wishlist/use-remove-item' import type { RemoveItemBody } from '../api/wishlist' import useCustomer from '../customer/use-customer' -import useWishlist, { UseWishlistOptions, Wishlist } from './use-wishlist' +import useWishlist from './use-wishlist' const defaultOpts = { url: '/api/bigcommerce/wishlist', @@ -15,7 +15,7 @@ export type RemoveItemInput = { id: string | number } -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, { itemId }, fetch @@ -28,10 +28,10 @@ export const fetcher: HookFetcher = ( } export function extendHook(customFetcher: typeof fetcher) { - const useRemoveItem = (opts?: UseWishlistOptions) => { + const useRemoveItem = (opts?: any) => { const { data: customer } = useCustomer() const { revalidate } = useWishlist(opts) - const fn = useWishlistRemoveItem( + const fn = useWishlistRemoveItem( defaultOpts, customFetcher ) diff --git a/framework/commerce/wishlist/use-add-item.tsx b/framework/commerce/wishlist/use-add-item.tsx index f6c069f2b..d9b513694 100644 --- a/framework/commerce/wishlist/use-add-item.tsx +++ b/framework/commerce/wishlist/use-add-item.tsx @@ -1,4 +1,11 @@ import useAction from '../utils/use-action' +import type { CartItemBody } from '../types' + +// Input expected by the action returned by the `useAddItem` hook +// export interface AddItemInput { +// includeProducts?: boolean +// } +export type AddItemInput = T const useAddItem = useAction diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx index 3d2971eed..83aeaa54c 100644 --- a/pages/product/[slug].tsx +++ b/pages/product/[slug].tsx @@ -61,7 +61,7 @@ export default function Slug({ return router.isFallback ? (

Loading...

// TODO (BC) Add Skeleton Views ) : ( - + ) } diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx index a3f25d0e7..6de798411 100644 --- a/pages/wishlist.tsx +++ b/pages/wishlist.tsx @@ -44,7 +44,7 @@ export default function Wishlist() { ) : ( data && data.items?.map((item) => ( - + )) )} From fe7d6df04f39f15c471a3a2f7343866efd94abf2 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 12:02:31 -0500 Subject: [PATCH 7/9] Added a MutationHandler --- framework/commerce/utils/types.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/framework/commerce/utils/types.ts b/framework/commerce/utils/types.ts index 98e4ebbae..a06aa0477 100644 --- a/framework/commerce/utils/types.ts +++ b/framework/commerce/utils/types.ts @@ -76,6 +76,29 @@ export type HookHandler< fetcher?: HookFetcherFn } +export type MutationHandler< + // Data obj returned by the hook and fetch operation + Data, + // Input expected by the hook + Input extends { [k: string]: unknown } = {}, + // Input expected before doing a fetch operation + FetchInput extends HookFetchInput = {}, + // Custom state added to the response object of SWR + State = {} +> = { + useHook?(context: { + input: Input & { swrOptions?: SwrOptions } + useCallback( + fn: (context?: { + input?: HookFetchInput | HookSwrInput + swrOptions?: SwrOptions + }) => Data + ): ResponseState + }): ResponseState & State + fetchOptions: HookFetcherOptions + fetcher?: HookFetcherFn +} + export type SwrOptions = ConfigInterface< Data, CommerceError, From c4870a05e8fd183c62e93ec8c389823480c52263 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 18:48:47 -0500 Subject: [PATCH 8/9] Moved the handlers to each hook --- framework/bigcommerce/cart/use-cart.tsx | 40 ++++- .../bigcommerce/customer/use-customer.tsx | 21 +++ framework/bigcommerce/product/use-search.tsx | 50 ++++++ framework/bigcommerce/provider.tsx | 167 +----------------- .../bigcommerce/wishlist/use-wishlist.tsx | 55 ++++++ 5 files changed, 171 insertions(+), 162 deletions(-) diff --git a/framework/bigcommerce/cart/use-cart.tsx b/framework/bigcommerce/cart/use-cart.tsx index 4f8a5cbcd..b5cc0cccf 100644 --- a/framework/bigcommerce/cart/use-cart.tsx +++ b/framework/bigcommerce/cart/use-cart.tsx @@ -1,4 +1,42 @@ -import useCart, { UseCart } from '@commerce/cart/use-cart' +import { useMemo } from 'react' +import { HookHandler } from '@commerce/utils/types' +import useCart, { UseCart, FetchCartInput } from '@commerce/cart/use-cart' +import { normalizeCart } from '../lib/normalize' +import type { Cart } from '../types' import type { BigcommerceProvider } from '..' export default useCart as UseCart + +export const handler: HookHandler< + Cart | null, + {}, + FetchCartInput, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/cart', + method: 'GET', + }, + async fetcher({ input: { cartId }, options, fetch }) { + const data = cartId ? await fetch(options) : null + return data && normalizeCart(data) + }, + useHook({ input, useData }) { + const response = useData({ + swrOptions: { revalidateOnFocus: false, ...input.swrOptions }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.lineItems.length ?? 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} diff --git a/framework/bigcommerce/customer/use-customer.tsx b/framework/bigcommerce/customer/use-customer.tsx index 95adb6fb3..3929002f7 100644 --- a/framework/bigcommerce/customer/use-customer.tsx +++ b/framework/bigcommerce/customer/use-customer.tsx @@ -1,4 +1,25 @@ +import { HookHandler } from '@commerce/utils/types' import useCustomer, { UseCustomer } from '@commerce/customer/use-customer' +import type { Customer, CustomerData } from '../api/customers' import type { BigcommerceProvider } from '..' export default useCustomer as UseCustomer + +export const handler: HookHandler = { + fetchOptions: { + url: '/api/bigcommerce/customers', + method: 'GET', + }, + async fetcher({ options, fetch }) { + const data = await fetch(options) + return data?.customer ?? null + }, + useHook({ input, useData }) { + return useData({ + swrOptions: { + revalidateOnFocus: false, + ...input.swrOptions, + }, + }) + }, +} diff --git a/framework/bigcommerce/product/use-search.tsx b/framework/bigcommerce/product/use-search.tsx index 52db6a72d..393a8c0b9 100644 --- a/framework/bigcommerce/product/use-search.tsx +++ b/framework/bigcommerce/product/use-search.tsx @@ -1,4 +1,54 @@ +import { HookHandler } from '@commerce/utils/types' import useSearch, { UseSearch } from '@commerce/products/use-search' +import type { SearchProductsData } from '../api/catalog/products' import type { BigcommerceProvider } from '..' export default useSearch as UseSearch + +export type SearchProductsInput = { + search?: string + categoryId?: number + brandId?: number + sort?: string +} + +export const handler: HookHandler< + SearchProductsData, + SearchProductsInput, + SearchProductsInput +> = { + fetchOptions: { + url: '/api/bigcommerce/catalog/products', + method: 'GET', + }, + fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) { + // Use a dummy base as we only care about the relative path + const url = new URL(options.url!, 'http://a') + + if (search) url.searchParams.set('search', search) + if (Number.isInteger(categoryId)) + url.searchParams.set('category', String(categoryId)) + if (Number.isInteger(brandId)) + url.searchParams.set('brand', String(brandId)) + if (sort) url.searchParams.set('sort', sort) + + return fetch({ + url: url.pathname + url.search, + method: options.method, + }) + }, + useHook({ input, useData }) { + return useData({ + input: [ + ['search', input.search], + ['categoryId', input.categoryId], + ['brandId', input.brandId], + ['sort', input.sort], + ], + swrOptions: { + revalidateOnFocus: false, + ...input.swrOptions, + }, + }) + }, +} diff --git a/framework/bigcommerce/provider.tsx b/framework/bigcommerce/provider.tsx index e8ac29cf5..a54fab0bb 100644 --- a/framework/bigcommerce/provider.tsx +++ b/framework/bigcommerce/provider.tsx @@ -1,13 +1,10 @@ -import { useMemo } from 'react' import { FetcherError } from '@commerce/utils/errors' -import type { Fetcher, HookHandler } from '@commerce/utils/types' -import type { FetchCartInput } from '@commerce/cart/use-cart' +import type { Fetcher } from '@commerce/utils/types' import { normalizeCart } from './lib/normalize' -import type { Wishlist } from './api/wishlist' -import type { Customer, CustomerData } from './api/customers' -import type { SearchProductsData } from './api/catalog/products' -import useCustomer from './customer/use-customer' -import type { Cart } from './types' +import { handler as useCart } from './cart/use-cart' +import { handler as useWishlist } from './wishlist/use-wishlist' +import { handler as useCustomer } from './customer/use-customer' +import { handler as useSearch } from './product/use-search' async function getText(res: Response) { try { @@ -46,158 +43,6 @@ const fetcher: Fetcher = async ({ throw await getError(res) } -const useCart: HookHandler< - Cart | null, - {}, - FetchCartInput, - { isEmpty?: boolean } -> = { - fetchOptions: { - url: '/api/bigcommerce/cart', - method: 'GET', - }, - async fetcher({ input: { cartId }, options, fetch }) { - const data = cartId ? await fetch(options) : null - return data && normalizeCart(data) - }, - useHook({ input, useData }) { - const response = useData({ - swrOptions: { revalidateOnFocus: false, ...input.swrOptions }, - }) - - return useMemo( - () => - Object.create(response, { - isEmpty: { - get() { - return (response.data?.lineItems.length ?? 0) <= 0 - }, - enumerable: true, - }, - }), - [response] - ) - }, -} - -const useWishlist: HookHandler< - Wishlist | null, - { includeProducts?: boolean }, - { customerId?: number; includeProducts: boolean }, - { isEmpty?: boolean } -> = { - fetchOptions: { - url: '/api/bigcommerce/wishlist', - method: 'GET', - }, - fetcher({ input: { customerId, includeProducts }, options, fetch }) { - if (!customerId) return null - - // Use a dummy base as we only care about the relative path - const url = new URL(options.url!, 'http://a') - - if (includeProducts) url.searchParams.set('products', '1') - - return fetch({ - url: url.pathname + url.search, - method: options.method, - }) - }, - useHook({ input, useData }) { - const { data: customer } = useCustomer() - const response = useData({ - input: [ - ['customerId', (customer as any)?.id], - ['includeProducts', input.includeProducts], - ], - swrOptions: { - revalidateOnFocus: false, - ...input.swrOptions, - }, - }) - - return useMemo( - () => - Object.create(response, { - isEmpty: { - get() { - return (response.data?.items?.length || 0) <= 0 - }, - enumerable: true, - }, - }), - [response] - ) - }, -} - -const useCustomerHandler: HookHandler = { - fetchOptions: { - url: '/api/bigcommerce/customers', - method: 'GET', - }, - async fetcher({ options, fetch }) { - const data = await fetch(options) - return data?.customer ?? null - }, - useHook({ input, useData }) { - return useData({ - swrOptions: { - revalidateOnFocus: false, - ...input.swrOptions, - }, - }) - }, -} - -export type SearchProductsInput = { - search?: string - categoryId?: number - brandId?: number - sort?: string -} - -const useSearch: HookHandler< - SearchProductsData, - SearchProductsInput, - SearchProductsInput -> = { - fetchOptions: { - url: '/api/bigcommerce/catalog/products', - method: 'GET', - }, - fetcher({ input: { search, categoryId, brandId, sort }, options, fetch }) { - // Use a dummy base as we only care about the relative path - const url = new URL(options.url!, 'http://a') - - if (search) url.searchParams.set('search', search) - if (Number.isInteger(categoryId)) - url.searchParams.set('category', String(categoryId)) - if (Number.isInteger(brandId)) - url.searchParams.set('brand', String(brandId)) - if (sort) url.searchParams.set('sort', sort) - - return fetch({ - url: url.pathname + url.search, - method: options.method, - }) - }, - useHook({ input, useData }) { - return useData({ - input: [ - ['search', input.search], - ['categoryId', input.categoryId], - ['brandId', input.brandId], - ['sort', input.sort], - ], - swrOptions: { - revalidateOnFocus: false, - ...input.swrOptions, - }, - }) - }, -} - export const bigcommerceProvider = { locale: 'en-us', cartCookie: 'bc_cartId', @@ -205,7 +50,7 @@ export const bigcommerceProvider = { cartNormalizer: normalizeCart, cart: { useCart }, wishlist: { useWishlist }, - customer: { useCustomer: useCustomerHandler }, + customer: { useCustomer }, products: { useSearch }, } diff --git a/framework/bigcommerce/wishlist/use-wishlist.tsx b/framework/bigcommerce/wishlist/use-wishlist.tsx index dfa3d9dbc..a93f0f6a4 100644 --- a/framework/bigcommerce/wishlist/use-wishlist.tsx +++ b/framework/bigcommerce/wishlist/use-wishlist.tsx @@ -1,4 +1,59 @@ +import { useMemo } from 'react' +import { HookHandler } from '@commerce/utils/types' import useWishlist, { UseWishlist } from '@commerce/wishlist/use-wishlist' +import type { Wishlist } from '../api/wishlist' +import useCustomer from '../customer/use-customer' import type { BigcommerceProvider } from '..' export default useWishlist as UseWishlist + +export const handler: HookHandler< + Wishlist | null, + { includeProducts?: boolean }, + { customerId?: number; includeProducts: boolean }, + { isEmpty?: boolean } +> = { + fetchOptions: { + url: '/api/bigcommerce/wishlist', + method: 'GET', + }, + fetcher({ input: { customerId, includeProducts }, options, fetch }) { + if (!customerId) return null + + // Use a dummy base as we only care about the relative path + const url = new URL(options.url!, 'http://a') + + if (includeProducts) url.searchParams.set('products', '1') + + return fetch({ + url: url.pathname + url.search, + method: options.method, + }) + }, + useHook({ input, useData }) { + const { data: customer } = useCustomer() + const response = useData({ + input: [ + ['customerId', (customer as any)?.id], + ['includeProducts', input.includeProducts], + ], + swrOptions: { + revalidateOnFocus: false, + ...input.swrOptions, + }, + }) + + return useMemo( + () => + Object.create(response, { + isEmpty: { + get() { + return (response.data?.items?.length || 0) <= 0 + }, + enumerable: true, + }, + }), + [response] + ) + }, +} From 75d485d35a14e5f81dc5ec6919b352a6d2c0b391 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Mon, 15 Feb 2021 18:50:52 -0500 Subject: [PATCH 9/9] Moved the fetcher to its own file --- .../bigcommerce/{provider.tsx => fetcher.ts} | 18 +----------------- framework/bigcommerce/provider.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 17 deletions(-) rename framework/bigcommerce/{provider.tsx => fetcher.ts} (64%) create mode 100644 framework/bigcommerce/provider.ts diff --git a/framework/bigcommerce/provider.tsx b/framework/bigcommerce/fetcher.ts similarity index 64% rename from framework/bigcommerce/provider.tsx rename to framework/bigcommerce/fetcher.ts index a54fab0bb..f8ca0c578 100644 --- a/framework/bigcommerce/provider.tsx +++ b/framework/bigcommerce/fetcher.ts @@ -1,10 +1,5 @@ import { FetcherError } from '@commerce/utils/errors' import type { Fetcher } from '@commerce/utils/types' -import { normalizeCart } from './lib/normalize' -import { handler as useCart } from './cart/use-cart' -import { handler as useWishlist } from './wishlist/use-wishlist' -import { handler as useCustomer } from './customer/use-customer' -import { handler as useSearch } from './product/use-search' async function getText(res: Response) { try { @@ -43,15 +38,4 @@ const fetcher: Fetcher = async ({ throw await getError(res) } -export const bigcommerceProvider = { - locale: 'en-us', - cartCookie: 'bc_cartId', - fetcher, - cartNormalizer: normalizeCart, - cart: { useCart }, - wishlist: { useWishlist }, - customer: { useCustomer }, - products: { useSearch }, -} - -export type BigcommerceProvider = typeof bigcommerceProvider +export default fetcher diff --git a/framework/bigcommerce/provider.ts b/framework/bigcommerce/provider.ts new file mode 100644 index 000000000..ee5630813 --- /dev/null +++ b/framework/bigcommerce/provider.ts @@ -0,0 +1,17 @@ +import { handler as useCart } from './cart/use-cart' +import { handler as useWishlist } from './wishlist/use-wishlist' +import { handler as useCustomer } from './customer/use-customer' +import { handler as useSearch } from './product/use-search' +import fetcher from './fetcher' + +export const bigcommerceProvider = { + locale: 'en-us', + cartCookie: 'bc_cartId', + fetcher, + cart: { useCart }, + wishlist: { useWishlist }, + customer: { useCustomer }, + products: { useSearch }, +} + +export type BigcommerceProvider = typeof bigcommerceProvider