diff --git a/lib/bigcommerce/api/operations/get-customer-wishlist.ts b/lib/bigcommerce/api/operations/get-customer-wishlist.ts index 1fc40f201..48e9e9c4d 100644 --- a/lib/bigcommerce/api/operations/get-customer-wishlist.ts +++ b/lib/bigcommerce/api/operations/get-customer-wishlist.ts @@ -1,8 +1,13 @@ import type { RecursivePartial, RecursiveRequired } from '../utils/types' -import { BigcommerceConfig, getConfig } from '..' import { definitions } from '../definitions/wishlist' +import { BigcommerceConfig, getConfig } from '..' +import getAllProducts, { ProductEdge } from './get-all-products' -export type Wishlist = definitions['wishlist_Full'] +export type Wishlist = Omit & { + items?: (NonNullable[0] & { + product?: ProductEdge['node'] + })[] +} export type GetCustomerWishlistResult< T extends { wishlist?: any } = { wishlist?: Wishlist } @@ -15,6 +20,7 @@ export type GetCustomerWishlistVariables = { async function getCustomerWishlist(opts: { variables: GetCustomerWishlistVariables config?: BigcommerceConfig + includeProducts?: boolean }): Promise async function getCustomerWishlist< @@ -24,25 +30,54 @@ async function getCustomerWishlist< url: string variables: V config?: BigcommerceConfig + includeProducts?: boolean }): Promise> async function getCustomerWishlist({ config, variables, + includeProducts, }: { url?: string variables: GetCustomerWishlistVariables config?: BigcommerceConfig + includeProducts?: boolean }): Promise { config = getConfig(config) - const { data } = await config.storeApiFetch< + const { data = [] } = await config.storeApiFetch< RecursivePartial<{ data: Wishlist[] }> >(`/v3/wishlists?customer_id=${variables.customerId}`) - const wishlists = (data as RecursiveRequired) ?? [] - const wishlist = wishlists[0] + const wishlist = data[0] - return { wishlist } + if (includeProducts && wishlist?.items?.length) { + const entityIds = wishlist.items + ?.map((item) => item?.product_id) + .filter((id): id is number => !!id) + + if (entityIds?.length) { + const graphqlData = await getAllProducts({ + variables: { first: 100, entityIds }, + config, + }) + // Put the products in an object that we can use to get them by id + const productsById = graphqlData.products.reduce<{ + [k: number]: ProductEdge + }>((prods, p) => { + prods[p.node.entityId] = p + return prods + }, {}) + // Populate the wishlist items with the graphql products + wishlist.items.forEach((item) => { + const product = item && productsById[item.product_id!] + if (item && product) { + item.product = product.node + } + }) + } + } + + return { wishlist: wishlist as RecursiveRequired } } export default getCustomerWishlist diff --git a/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts b/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts index a77cf4467..3eb3000cc 100644 --- a/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts +++ b/lib/bigcommerce/api/wishlist/handlers/get-wishlist.ts @@ -1,11 +1,11 @@ import getCustomerId from '../../operations/get-customer-id' -import type { Wishlist, WishlistHandlers } from '..' import getCustomerWishlist from '../../operations/get-customer-wishlist' +import type { Wishlist, WishlistHandlers } from '..' // Return wishlist info const getWishlist: WishlistHandlers['getWishlist'] = async ({ res, - body: { customerToken }, + body: { customerToken, includeProducts }, config, }) => { let result: { data?: Wishlist } = {} @@ -24,8 +24,10 @@ const getWishlist: WishlistHandlers['getWishlist'] = async ({ const { wishlist } = await getCustomerWishlist({ variables: { customerId }, + includeProducts, config, }) + result = { data: wishlist } } diff --git a/lib/bigcommerce/api/wishlist/index.ts b/lib/bigcommerce/api/wishlist/index.ts index 79f0a9c1a..9be4e7d5f 100644 --- a/lib/bigcommerce/api/wishlist/index.ts +++ b/lib/bigcommerce/api/wishlist/index.ts @@ -4,10 +4,12 @@ import createApiHandler, { BigcommerceHandler, } from '../utils/create-api-handler' import { BigcommerceApiError } from '../utils/errors' +import type { Wishlist } from '../operations/get-customer-wishlist' import getWishlist from './handlers/get-wishlist' import addItem from './handlers/add-item' import removeItem from './handlers/remove-item' -import { definitions } from '../definitions/wishlist' + +export type { Wishlist } export type ItemBody = { productId: number @@ -27,10 +29,11 @@ export type WishlistBody = { export type AddWishlistBody = { wishlist: WishlistBody } -export type Wishlist = definitions['wishlist_Full'] - export type WishlistHandlers = { - getWishlist: BigcommerceHandler + getWishlist: BigcommerceHandler< + Wishlist, + { customerToken?: string; includeProducts?: boolean } + > addItem: BigcommerceHandler< Wishlist, { customerToken?: string } & Partial @@ -58,7 +61,10 @@ const wishlistApi: BigcommerceApiHandler = async ( try { // Return current wishlist info if (req.method === 'GET') { - const body = { customerToken } + const body = { + customerToken, + includeProducts: req.query.products === '1', + } return await handlers['getWishlist']({ req, res, config, body }) } diff --git a/lib/bigcommerce/wishlist/use-wishlist.tsx b/lib/bigcommerce/wishlist/use-wishlist.tsx index ac2f9d496..c3f8b6100 100644 --- a/lib/bigcommerce/wishlist/use-wishlist.tsx +++ b/lib/bigcommerce/wishlist/use-wishlist.tsx @@ -11,23 +11,44 @@ const defaultOpts = { export type { Wishlist } -export const fetcher: HookFetcher = ( +export interface UseWishlistOptions { + includeProducts?: boolean +} + +export interface UseWishlistInput extends UseWishlistOptions { + customerId?: number +} + +export const fetcher: HookFetcher = ( options, - { customerId }, + { customerId, includeProducts }, fetch ) => { - return customerId ? fetch({ ...defaultOpts, ...options }) : null + if (!customerId) return null + + // Use a dummy base as we only care about the relative path + const url = new URL(options?.url ?? defaultOpts.url, 'http://a') + + if (includeProducts) url.searchParams.set('products', '1') + + return fetch({ + url: url.pathname + url.search, + method: options?.method ?? defaultOpts.method, + }) } export function extendHook( customFetcher: typeof fetcher, - swrOptions?: SwrOptions + swrOptions?: SwrOptions ) { - const useWishlists = () => { + const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => { const { data: customer } = useCustomer() const response = useCommerceWishlist( defaultOpts, - [['customerId', customer?.entityId]], + [ + ['customerId', customer?.entityId], + ['includeProducts', includeProducts], + ], customFetcher, { revalidateOnFocus: false, @@ -47,9 +68,9 @@ export function extendHook( return response } - useWishlists.extend = extendHook + useWishlist.extend = extendHook - return useWishlists + return useWishlist } export default extendHook(fetcher) diff --git a/lib/commerce/utils/types.ts b/lib/commerce/utils/types.ts index 5fd18d46d..b983d3391 100644 --- a/lib/commerce/utils/types.ts +++ b/lib/commerce/utils/types.ts @@ -21,4 +21,4 @@ export type HookFetcherOptions = { method?: string } -export type HookInput = [string, string | number | undefined][] +export type HookInput = [string, string | number | boolean | undefined][] diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx index aef363e94..2cc61cb6e 100644 --- a/pages/wishlist.tsx +++ b/pages/wishlist.tsx @@ -20,7 +20,8 @@ export default function Home({ categories, brands, }: InferGetStaticPropsType) { - const { data } = useWishlist() + const { data } = useWishlist({ includeProducts: true }) + console.log(data) return (