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 ? '' : ', '}
))}
diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx
index c7f07bf48..677757b7b 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'
diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx
index 8d4402271..5784e4b1a 100644
--- a/components/product/ProductCard/ProductCard.tsx
+++ b/components/product/ProductCard/ProductCard.tsx
@@ -1,6 +1,7 @@
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'
diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx
index 65fa4d93f..61beda7fe 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,8 +42,8 @@ const ProductView: FC = ({ product }) => {
setLoading(true)
try {
await addItem({
- productId: product.id,
- variantId: variant ? variant.id : product.variants[0].id,
+ productId: String(product.id),
+ variantId: String(variant ? variant.id : product.variants[0].id),
})
openSidebar()
setLoading(false)
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..bedd773b0 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'
@@ -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
}, {})
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/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/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/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/fetcher.ts b/framework/bigcommerce/fetcher.ts
new file mode 100644
index 000000000..f8ca0c578
--- /dev/null
+++ b/framework/bigcommerce/fetcher.ts
@@ -0,0 +1,41 @@
+import { FetcherError } from '@commerce/utils/errors'
+import type { Fetcher } from '@commerce/utils/types'
+
+async function getText(res: Response) {
+ try {
+ return (await res.text()) || res.statusText
+ } catch (error) {
+ return res.statusText
+ }
+}
+
+async function getError(res: Response) {
+ if (res.headers.get('Content-Type')?.includes('application/json')) {
+ const data = await res.json()
+ return new FetcherError({ errors: data.errors, status: res.status })
+ }
+ return new FetcherError({ message: await getText(res), status: res.status })
+}
+
+const fetcher: Fetcher = async ({
+ url,
+ method = 'GET',
+ variables,
+ body: bodyObj,
+}) => {
+ const hasBody = Boolean(variables || bodyObj)
+ const body = hasBody
+ ? JSON.stringify(variables ? { variables } : bodyObj)
+ : undefined
+ const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined
+ const res = await fetch(url!, { method, body, headers })
+
+ if (res.ok) {
+ const { data } = await res.json()
+ return data
+ }
+
+ throw await getError(res)
+}
+
+export default fetcher
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/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/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.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
diff --git a/framework/bigcommerce/provider.tsx b/framework/bigcommerce/provider.tsx
deleted file mode 100644
index 6fd02e304..000000000
--- a/framework/bigcommerce/provider.tsx
+++ /dev/null
@@ -1,212 +0,0 @@
-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 { 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'
-
-async function getText(res: Response) {
- try {
- return (await res.text()) || res.statusText
- } catch (error) {
- return res.statusText
- }
-}
-
-async function getError(res: Response) {
- if (res.headers.get('Content-Type')?.includes('application/json')) {
- const data = await res.json()
- return new FetcherError({ errors: data.errors, status: res.status })
- }
- return new FetcherError({ message: await getText(res), status: res.status })
-}
-
-const fetcher: Fetcher = async ({
- url,
- method = 'GET',
- variables,
- body: bodyObj,
-}) => {
- const hasBody = Boolean(variables || bodyObj)
- const body = hasBody
- ? JSON.stringify(variables ? { variables } : bodyObj)
- : undefined
- const headers = hasBody ? { 'Content-Type': 'application/json' } : undefined
- const res = await fetch(url!, { method, body, headers })
-
- if (res.ok) {
- const { data } = await res.json()
- return data
- }
-
- 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?.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',
- fetcher,
- cartNormalizer: normalizeCart,
- cart: { useCart },
- wishlist: { useWishlist },
- customer: { useCustomer: useCustomerHandler },
- products: { useSearch },
-}
-
-export type BigcommerceProvider = typeof bigcommerceProvider
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/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]
+ )
+ },
+}
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
+}
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,
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) => (
-
+
))
)}