diff --git a/framework/bigcommerce/api/endpoints/cart/index.ts b/framework/bigcommerce/api/endpoints/cart/index.ts index c96fe9761..ae2414d70 100644 --- a/framework/bigcommerce/api/endpoints/cart/index.ts +++ b/framework/bigcommerce/api/endpoints/cart/index.ts @@ -1,4 +1,5 @@ -import type { GetAPISchema } from '@commerce/api' +import { GetAPISchema, createEndpoint } from '@commerce/api' +import cartEndpoint from '@commerce/api/endpoints/cart' import type { CartSchema } from '../../../types/cart' import type { BigcommerceAPI } from '../..' import getCart from './get-cart' @@ -10,4 +11,16 @@ export type CartAPI = GetAPISchema export type CartEndpoint = CartAPI['endpoint'] -export const handlers = { getCart, addItem, updateItem, removeItem } +export const handlers: CartEndpoint['handlers'] = { + getCart, + addItem, + updateItem, + removeItem, +} + +const cartApi = createEndpoint({ + handler: cartEndpoint, + handlers, +}) + +export default cartApi diff --git a/framework/bigcommerce/api/endpoints/customer/index.ts b/framework/bigcommerce/api/endpoints/customer/index.ts index cbc70fa80..cb0f6787a 100644 --- a/framework/bigcommerce/api/endpoints/customer/index.ts +++ b/framework/bigcommerce/api/endpoints/customer/index.ts @@ -1,4 +1,5 @@ -import type { GetAPISchema } from '@commerce/api' +import { GetAPISchema, createEndpoint } from '@commerce/api' +import customerEndpoint from '@commerce/api/endpoints/customer' import type { CustomerSchema } from '../../../types/customer' import type { BigcommerceAPI } from '../..' import getLoggedInCustomer from './get-logged-in-customer' @@ -7,4 +8,11 @@ export type CustomerAPI = GetAPISchema export type CustomerEndpoint = CustomerAPI['endpoint'] -export const handlers = { getLoggedInCustomer } +export const handlers: CustomerEndpoint['handlers'] = { getLoggedInCustomer } + +const customerApi = createEndpoint({ + handler: customerEndpoint, + handlers, +}) + +export default customerApi diff --git a/framework/bigcommerce/api/endpoints/login/index.ts b/framework/bigcommerce/api/endpoints/login/index.ts index 5bd6e469c..2b454c7c2 100644 --- a/framework/bigcommerce/api/endpoints/login/index.ts +++ b/framework/bigcommerce/api/endpoints/login/index.ts @@ -1,4 +1,5 @@ -import type { GetAPISchema } from '@commerce/api' +import { GetAPISchema, createEndpoint } from '@commerce/api' +import loginEndpoint from '@commerce/api/endpoints/login' import type { LoginSchema } from '../../../types/login' import type { BigcommerceAPI } from '../..' import login from './login' @@ -7,4 +8,11 @@ export type LoginAPI = GetAPISchema export type LoginEndpoint = LoginAPI['endpoint'] -export const handlers = { login } +export const handlers: LoginEndpoint['handlers'] = { login } + +const loginApi = createEndpoint({ + handler: loginEndpoint, + handlers, +}) + +export default loginApi diff --git a/framework/bigcommerce/api/endpoints/logout/index.ts b/framework/bigcommerce/api/endpoints/logout/index.ts index d70bcb0c3..0dbb23bab 100644 --- a/framework/bigcommerce/api/endpoints/logout/index.ts +++ b/framework/bigcommerce/api/endpoints/logout/index.ts @@ -1,4 +1,5 @@ -import type { GetAPISchema } from '@commerce/api' +import { GetAPISchema, createEndpoint } from '@commerce/api' +import logoutEndpoint from '@commerce/api/endpoints/logout' import type { LogoutSchema } from '../../../types/logout' import type { BigcommerceAPI } from '../..' import logout from './logout' @@ -7,4 +8,11 @@ export type LogoutAPI = GetAPISchema export type LogoutEndpoint = LogoutAPI['endpoint'] -export const handlers = { logout } +export const handlers: LogoutEndpoint['handlers'] = { logout } + +const logoutApi = createEndpoint({ + handler: logoutEndpoint, + handlers, +}) + +export default logoutApi diff --git a/framework/bigcommerce/api/endpoints/signup/index.ts b/framework/bigcommerce/api/endpoints/signup/index.ts index 2efdff641..6ce8be271 100644 --- a/framework/bigcommerce/api/endpoints/signup/index.ts +++ b/framework/bigcommerce/api/endpoints/signup/index.ts @@ -1,4 +1,5 @@ -import type { GetAPISchema } from '@commerce/api' +import { GetAPISchema, createEndpoint } from '@commerce/api' +import signupEndpoint from '@commerce/api/endpoints/signup' import type { SignupSchema } from '../../../types/signup' import type { BigcommerceAPI } from '../..' import signup from './signup' @@ -7,4 +8,11 @@ export type SignupAPI = GetAPISchema export type SignupEndpoint = SignupAPI['endpoint'] -export const handlers = { signup } +export const handlers: SignupEndpoint['handlers'] = { signup } + +const singupApi = createEndpoint({ + handler: signupEndpoint, + handlers, +}) + +export default singupApi diff --git a/framework/bigcommerce/api/endpoints/wishlist/add-item.ts b/framework/bigcommerce/api/endpoints/wishlist/add-item.ts new file mode 100644 index 000000000..c2fdd9eff --- /dev/null +++ b/framework/bigcommerce/api/endpoints/wishlist/add-item.ts @@ -0,0 +1,56 @@ +import getCustomerWishlist from '../../../customer/get-customer-wishlist' +import { parseWishlistItem } from '../../utils/parse-item' +import getCustomerId from './utils/get-customer-id' +import type { WishlistEndpoint } from '.' + +// Return wishlist info +const addItem: WishlistEndpoint['handlers']['addItem'] = async ({ + res, + body: { customerToken, item }, + config, +}) => { + if (!item) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Missing item' }], + }) + } + + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + + if (!customerId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const { wishlist } = await getCustomerWishlist({ + variables: { customerId }, + config, + }) + const options = { + method: 'POST', + body: JSON.stringify( + wishlist + ? { + items: [parseWishlistItem(item)], + } + : { + name: 'Wishlist', + customer_id: customerId, + items: [parseWishlistItem(item)], + is_public: false, + } + ), + } + + const { data } = wishlist + ? await config.storeApiFetch(`/v3/wishlists/${wishlist.id}/items`, options) + : await config.storeApiFetch('/v3/wishlists', options) + + res.status(200).json({ data }) +} + +export default addItem diff --git a/framework/bigcommerce/api/endpoints/wishlist/get-wishlist.ts b/framework/bigcommerce/api/endpoints/wishlist/get-wishlist.ts new file mode 100644 index 000000000..43dcc0bfb --- /dev/null +++ b/framework/bigcommerce/api/endpoints/wishlist/get-wishlist.ts @@ -0,0 +1,38 @@ +import type { Wishlist } from '../../../types/wishlist' +import type { WishlistEndpoint } from '.' +import getCustomerId from './utils/get-customer-id' +import getCustomerWishlist from '../../../customer/get-customer-wishlist' + +// Return wishlist info +const getWishlist: WishlistEndpoint['handlers']['getWishlist'] = async ({ + res, + body: { customerToken, includeProducts }, + config, +}) => { + let result: { data?: Wishlist } = {} + + if (customerToken) { + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + + if (!customerId) { + // If the customerToken is invalid, then this request is too + return res.status(404).json({ + data: null, + errors: [{ message: 'Wishlist not found' }], + }) + } + + const { wishlist } = await getCustomerWishlist({ + variables: { customerId }, + includeProducts, + config, + }) + + result = { data: wishlist } + } + + res.status(200).json({ data: result.data ?? null }) +} + +export default getWishlist diff --git a/framework/bigcommerce/api/endpoints/wishlist/index.ts b/framework/bigcommerce/api/endpoints/wishlist/index.ts new file mode 100644 index 000000000..31af234ce --- /dev/null +++ b/framework/bigcommerce/api/endpoints/wishlist/index.ts @@ -0,0 +1,24 @@ +import { GetAPISchema, createEndpoint } from '@commerce/api' +import wishlistEndpoint from '@commerce/api/endpoints/wishlist' +import type { WishlistSchema } from '../../../types/wishlist' +import type { BigcommerceAPI } from '../..' +import getWishlist from './get-wishlist' +import addItem from './add-item' +import removeItem from './remove-item' + +export type WishlistAPI = GetAPISchema + +export type WishlistEndpoint = WishlistAPI['endpoint'] + +export const handlers: WishlistEndpoint['handlers'] = { + getWishlist, + addItem, + removeItem, +} + +const wishlistApi = createEndpoint({ + handler: wishlistEndpoint, + handlers, +}) + +export default wishlistApi diff --git a/framework/bigcommerce/api/endpoints/wishlist/remove-item.ts b/framework/bigcommerce/api/endpoints/wishlist/remove-item.ts new file mode 100644 index 000000000..7a243b322 --- /dev/null +++ b/framework/bigcommerce/api/endpoints/wishlist/remove-item.ts @@ -0,0 +1,38 @@ +import type { Wishlist } from '../../../types/wishlist' +import getCustomerWishlist from '../../../customer/get-customer-wishlist' +import getCustomerId from './utils/get-customer-id' +import type { WishlistEndpoint } from '.' + +// Return wishlist info +const removeItem: WishlistEndpoint['handlers']['removeItem'] = async ({ + res, + body: { customerToken, itemId }, + config, +}) => { + const customerId = + customerToken && (await getCustomerId({ customerToken, config })) + const { wishlist } = + (customerId && + (await getCustomerWishlist({ + variables: { customerId }, + config, + }))) || + {} + + if (!wishlist || !itemId) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + + const result = await config.storeApiFetch<{ data: Wishlist } | null>( + `/v3/wishlists/${wishlist.id}/items/${itemId}`, + { method: 'DELETE' } + ) + const data = result?.data ?? null + + res.status(200).json({ data }) +} + +export default removeItem diff --git a/framework/bigcommerce/customer/get-customer-id.ts b/framework/bigcommerce/api/endpoints/wishlist/utils/get-customer-id.ts similarity index 76% rename from framework/bigcommerce/customer/get-customer-id.ts rename to framework/bigcommerce/api/endpoints/wishlist/utils/get-customer-id.ts index 65ce5a6a8..5f9fc49df 100644 --- a/framework/bigcommerce/customer/get-customer-id.ts +++ b/framework/bigcommerce/api/endpoints/wishlist/utils/get-customer-id.ts @@ -1,5 +1,5 @@ -import { GetCustomerIdQuery } from '../schema' -import { BigcommerceConfig, getConfig } from '../api' +import type { GetCustomerIdQuery } from '../../../../schema' +import type { BigcommerceConfig } from '../../..' export const getCustomerIdQuery = /* GraphQL */ ` query getCustomerId { @@ -14,10 +14,8 @@ async function getCustomerId({ config, }: { customerToken: string - config?: BigcommerceConfig + config: BigcommerceConfig }): Promise { - config = getConfig(config) - const { data } = await config.fetch( getCustomerIdQuery, undefined, diff --git a/framework/bigcommerce/api/index.ts b/framework/bigcommerce/api/index.ts index 2dcd31d4f..9eeea5b49 100644 --- a/framework/bigcommerce/api/index.ts +++ b/framework/bigcommerce/api/index.ts @@ -4,7 +4,6 @@ import { CommerceAPI, CommerceAPIConfig, getCommerceApi as commerceApi, - getEndpoint, } from '@commerce/api' import fetchGraphqlApi from './utils/fetch-graphql-api' import fetchStoreApi from './utils/fetch-store-api' @@ -15,6 +14,7 @@ import type { LoginAPI } from './endpoints/login' import type { LogoutAPI } from './endpoints/logout' import type { SignupAPI } from './endpoints/signup' import type { ProductsAPI } from './endpoints/catalog/products' +import type { WishlistAPI } from './endpoints/wishlist' import login from './operations/login' import getAllPages from './operations/get-all-pages' @@ -127,24 +127,14 @@ export type APIs = | LogoutAPI | SignupAPI | ProductsAPI + | WishlistAPI export type BigcommerceAPI

= CommerceAPI

export function getCommerceApi

( customProvider: P = provider as any -) { - const api: BigcommerceAPI

= commerceApi(customProvider) - - return Object.assign(api, { - endpoint( - context: E['endpoint'] & { - config?: P['config'] - options?: E['schema']['endpoint']['options'] - } - ): NextApiHandler { - return getEndpoint(api, context) - }, - }) +): BigcommerceAPI

{ + return commerceApi(customProvider) } export function getConfig(userConfig?: Partial) { diff --git a/framework/bigcommerce/api/wishlist/handlers/add-item.ts b/framework/bigcommerce/api/wishlist/handlers/add-item.ts index 00d7b06bd..cbf0ec9d6 100644 --- a/framework/bigcommerce/api/wishlist/handlers/add-item.ts +++ b/framework/bigcommerce/api/wishlist/handlers/add-item.ts @@ -1,5 +1,5 @@ import type { WishlistHandlers } from '..' -import getCustomerId from '../../../customer/get-customer-id' +import getCustomerId from '../../endpoints/wishlist/utils/get-customer-id' import getCustomerWishlist from '../../../customer/get-customer-wishlist' import { parseWishlistItem } from '../../utils/parse-item' diff --git a/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts b/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts index 3737c033a..a1c74fb29 100644 --- a/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts +++ b/framework/bigcommerce/api/wishlist/handlers/get-wishlist.ts @@ -1,4 +1,4 @@ -import getCustomerId from '../../../customer/get-customer-id' +import getCustomerId from '../../endpoints/wishlist/utils/get-customer-id' import getCustomerWishlist from '../../../customer/get-customer-wishlist' import type { Wishlist, WishlistHandlers } from '..' diff --git a/framework/bigcommerce/api/wishlist/handlers/remove-item.ts b/framework/bigcommerce/api/wishlist/handlers/remove-item.ts index a9cfd9db5..ea5764a28 100644 --- a/framework/bigcommerce/api/wishlist/handlers/remove-item.ts +++ b/framework/bigcommerce/api/wishlist/handlers/remove-item.ts @@ -1,4 +1,4 @@ -import getCustomerId from '../../../customer/get-customer-id' +import getCustomerId from '../../endpoints/wishlist/utils/get-customer-id' import getCustomerWishlist, { Wishlist, } from '../../../customer/get-customer-wishlist' diff --git a/framework/bigcommerce/types/wishlist.ts b/framework/bigcommerce/types/wishlist.ts new file mode 100644 index 000000000..9c98a8df4 --- /dev/null +++ b/framework/bigcommerce/types/wishlist.ts @@ -0,0 +1,22 @@ +import * as Core from '@commerce/types/wishlist' +import { definitions } from '../api/definitions/wishlist' +import type { ProductEdge } from '../product/get-all-products' + +export * from '@commerce/types/wishlist' + +export type WishlistItem = NonNullable< + definitions['wishlist_Full']['items'] +>[0] & { + product?: ProductEdge['node'] +} + +export type Wishlist = Omit & { + items?: WishlistItem[] +} + +export type WishlistTypes = { + wishlist: Wishlist + itemBody: Core.WishlistItemBody +} + +export type WishlistSchema = Core.WishlistSchema diff --git a/framework/commerce/api/endpoints/cart.ts b/framework/commerce/api/endpoints/cart.ts index e5a05dbd6..ca39e7da3 100644 --- a/framework/commerce/api/endpoints/cart.ts +++ b/framework/commerce/api/endpoints/cart.ts @@ -5,7 +5,7 @@ import type { GetAPISchema } from '..' const cartEndpoint: GetAPISchema< any, - CartSchema + CartSchema >['endpoint']['handler'] = async (ctx) => { const { req, res, handlers, config } = ctx diff --git a/framework/commerce/api/endpoints/customer.ts b/framework/commerce/api/endpoints/customer.ts index cf4699d2a..6372c494f 100644 --- a/framework/commerce/api/endpoints/customer.ts +++ b/framework/commerce/api/endpoints/customer.ts @@ -5,7 +5,7 @@ import type { GetAPISchema } from '..' const customerEndpoint: GetAPISchema< any, - CustomerSchema + CustomerSchema >['endpoint']['handler'] = async (ctx) => { const { req, res, handlers } = ctx diff --git a/framework/commerce/api/endpoints/login.ts b/framework/commerce/api/endpoints/login.ts index 946df0d2c..bc071b751 100644 --- a/framework/commerce/api/endpoints/login.ts +++ b/framework/commerce/api/endpoints/login.ts @@ -5,7 +5,7 @@ import type { GetAPISchema } from '..' const loginEndpoint: GetAPISchema< any, - LoginSchema + LoginSchema >['endpoint']['handler'] = async (ctx) => { const { req, res, handlers } = ctx diff --git a/framework/commerce/api/endpoints/wishlist.ts b/framework/commerce/api/endpoints/wishlist.ts new file mode 100644 index 000000000..233ac5294 --- /dev/null +++ b/framework/commerce/api/endpoints/wishlist.ts @@ -0,0 +1,58 @@ +import type { WishlistSchema } from '../../types/wishlist' +import { CommerceAPIError } from '../utils/errors' +import isAllowedOperation from '../utils/is-allowed-operation' +import type { GetAPISchema } from '..' + +const wishlistEndpoint: GetAPISchema< + any, + WishlistSchema +>['endpoint']['handler'] = async (ctx) => { + const { req, res, handlers, config } = ctx + + if ( + !isAllowedOperation(req, res, { + GET: handlers['getWishlist'], + POST: handlers['addItem'], + DELETE: handlers['removeItem'], + }) + ) { + return + } + + const { cookies } = req + const customerToken = cookies[config.customerCookie] + + try { + // Return current wishlist info + if (req.method === 'GET') { + const body = { + customerToken, + includeProducts: req.query.products === '1', + } + return await handlers['getWishlist']({ ...ctx, body }) + } + + // Add an item to the wishlist + if (req.method === 'POST') { + const body = { ...req.body, customerToken } + return await handlers['addItem']({ ...ctx, body }) + } + + // Remove an item from the wishlist + if (req.method === 'DELETE') { + const body = { ...req.body, customerToken } + return await handlers['removeItem']({ ...ctx, body }) + } + } catch (error) { + console.error(error) + + const message = + error instanceof CommerceAPIError + ? 'An unexpected error ocurred with the Commerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +export default wishlistEndpoint diff --git a/framework/commerce/types/wishlist.ts b/framework/commerce/types/wishlist.ts new file mode 100644 index 000000000..70f900362 --- /dev/null +++ b/framework/commerce/types/wishlist.ts @@ -0,0 +1,32 @@ +// TODO: define this type +export type Wishlist = any + +export type WishlistItemBody = { + variantId: string + productId: string +} + +export type WishlistTypes = { + wishlist: Wishlist + itemBody: WishlistItemBody +} + +export type WishlistSchema = { + endpoint: { + options: {} + handlers: { + getWishlist: { + data: T['wishlist'] | null + body: { customerToken?: string; includeProducts?: boolean } + } + addItem: { + data: T['wishlist'] + body: { customerToken?: string; item: T['itemBody'] } + } + removeItem: { + data: T['wishlist'] | null + body: { customerToken?: string; itemId: string } + } + } + } +} diff --git a/pages/api/bigcommerce/catalog/products.ts b/pages/api/bigcommerce/catalog/products.ts deleted file mode 100644 index ac342c82a..000000000 --- a/pages/api/bigcommerce/catalog/products.ts +++ /dev/null @@ -1,3 +0,0 @@ -import catalogProductsApi from '@framework/api/catalog/products' - -export default catalogProductsApi() diff --git a/pages/api/bigcommerce/wishlist.ts b/pages/api/bigcommerce/wishlist.ts deleted file mode 100644 index 0d6a895a5..000000000 --- a/pages/api/bigcommerce/wishlist.ts +++ /dev/null @@ -1,3 +0,0 @@ -import wishlistApi from '@framework/api/wishlist' - -export default wishlistApi() diff --git a/pages/api/cart.ts b/pages/api/cart.ts index e05ddc2f2..642891107 100644 --- a/pages/api/cart.ts +++ b/pages/api/cart.ts @@ -1,8 +1,4 @@ -import cart from '@commerce/api/endpoints/cart' -import { CartAPI, handlers } from '@framework/api/endpoints/cart' +import cartApi from '@framework/api/endpoints/cart' import commerce from '@lib/api/commerce' -export default commerce.endpoint({ - handler: cart as CartAPI['endpoint']['handler'], - handlers, -}) +export default cartApi(commerce) diff --git a/pages/api/customer.ts b/pages/api/customer.ts index 85a0c893e..0c86e76e5 100644 --- a/pages/api/customer.ts +++ b/pages/api/customer.ts @@ -1,8 +1,4 @@ -import customer from '@commerce/api/endpoints/customer' -import { CustomerAPI, handlers } from '@framework/api/endpoints/customer' +import customerApi from '@framework/api/endpoints/customer' import commerce from '@lib/api/commerce' -export default commerce.endpoint({ - handler: customer as CustomerAPI['endpoint']['handler'], - handlers, -}) +export default customerApi(commerce) diff --git a/pages/api/login.ts b/pages/api/login.ts index 982944654..9d0b6ae57 100644 --- a/pages/api/login.ts +++ b/pages/api/login.ts @@ -1,8 +1,4 @@ -import login from '@commerce/api/endpoints/login' -import { LoginAPI, handlers } from '@framework/api/endpoints/login' +import loginApi from '@framework/api/endpoints/login' import commerce from '@lib/api/commerce' -export default commerce.endpoint({ - handler: login as LoginAPI['endpoint']['handler'], - handlers, -}) +export default loginApi(commerce) diff --git a/pages/api/logout.ts b/pages/api/logout.ts index 012ef2b0d..0cf0fc4d2 100644 --- a/pages/api/logout.ts +++ b/pages/api/logout.ts @@ -1,8 +1,4 @@ -import logout from '@commerce/api/endpoints/logout' -import { LogoutAPI, handlers } from '@framework/api/endpoints/logout' +import logoutApi from '@framework/api/endpoints/logout' import commerce from '@lib/api/commerce' -export default commerce.endpoint({ - handler: logout as LogoutAPI['endpoint']['handler'], - handlers, -}) +export default logoutApi(commerce) diff --git a/pages/api/signup.ts b/pages/api/signup.ts index 8b069d0ab..e19d67ee8 100644 --- a/pages/api/signup.ts +++ b/pages/api/signup.ts @@ -1,8 +1,4 @@ -import signup from '@commerce/api/endpoints/signup' -import { SignupAPI, handlers } from '@framework/api/endpoints/signup' +import singupApi from '@framework/api/endpoints/signup' import commerce from '@lib/api/commerce' -export default commerce.endpoint({ - handler: signup as SignupAPI['endpoint']['handler'], - handlers, -}) +export default singupApi(commerce) diff --git a/pages/api/wishlist.ts b/pages/api/wishlist.ts new file mode 100644 index 000000000..3b9681209 --- /dev/null +++ b/pages/api/wishlist.ts @@ -0,0 +1,4 @@ +import wishlistApi from '@framework/api/endpoints/wishlist' +import commerce from '@lib/api/commerce' + +export default wishlistApi(commerce)