diff --git a/codegen.json b/codegen.json index cce0f4f8b..e08292091 100644 --- a/codegen.json +++ b/codegen.json @@ -8,7 +8,7 @@ }, "documents": [ { - "./lib/bigcommerce/api/{operations,fragments}/**/*.ts": { + "./lib/bigcommerce/api/**/*.ts": { "noRequire": true } } diff --git a/lib/bigcommerce/api/cart/index.ts b/lib/bigcommerce/api/cart/index.ts index f2f174b84..4f6062674 100644 --- a/lib/bigcommerce/api/cart/index.ts +++ b/lib/bigcommerce/api/cart/index.ts @@ -80,19 +80,19 @@ const cartApi: BigcommerceApiHandler = async ( // Create or add an item to the cart if (req.method === 'POST') { - const body = { cartId, ...req.body } + const body = { ...req.body, cartId } return await handlers['addItem']({ req, res, config, body }) } // Update item in cart if (req.method === 'PUT') { - const body = { cartId, ...req.body } + const body = { ...req.body, cartId } return await handlers['updateItem']({ req, res, config, body }) } // Remove an item from the cart if (req.method === 'DELETE') { - const body = { cartId, ...req.body } + const body = { ...req.body, cartId } return await handlers['removeItem']({ req, res, config, body }) } } catch (error) { diff --git a/lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts b/lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts new file mode 100644 index 000000000..99e9191f5 --- /dev/null +++ b/lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts @@ -0,0 +1,44 @@ +import { GetLoggedInCustomerQuery } from '@lib/bigcommerce/schema' +import type { CustomersHandlers } from '..' + +export const getLoggedInCustomerQuery = /* GraphQL */ ` + query getLoggedInCustomer { + customer { + entityId + firstName + lastName + email + company + customerGroupId + notes + phone + addressCount + attributeCount + storeCredit { + value + currencyCode + } + } + } +` + +const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({ + res, + config, +}) => { + const data = await config.fetch( + getLoggedInCustomerQuery + ) + const { customer } = data + + if (!customer) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Customer not found', code: 'not_found' }], + }) + } + + res.status(200).json({ data: { customer } }) +} + +export default getLoggedInCustomer diff --git a/lib/bigcommerce/api/customers/handlers/login.ts b/lib/bigcommerce/api/customers/handlers/login.ts new file mode 100644 index 000000000..787c055f8 --- /dev/null +++ b/lib/bigcommerce/api/customers/handlers/login.ts @@ -0,0 +1,26 @@ +import login from '../../operations/login' +import type { LoginHandlers } from '../login' + +const loginHandler: LoginHandlers['login'] = async ({ + res, + body: { email, password }, + config, +}) => { + // TODO: Add proper validations with something like Ajv + if (!(email && password)) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Invalid request' }], + }) + } + // TODO: validate the password and email + // Passwords must be at least 7 characters and contain both alphabetic + // and numeric characters. + + // TODO: Currently not working, fix this asap. + const loginData = await login({ variables: { email, password }, config }) + + res.status(200).json({ data: null }) +} + +export default loginHandler diff --git a/lib/bigcommerce/api/customers/handlers/create-customer.ts b/lib/bigcommerce/api/customers/handlers/signup.ts similarity index 90% rename from lib/bigcommerce/api/customers/handlers/create-customer.ts rename to lib/bigcommerce/api/customers/handlers/signup.ts index a666467ab..85400e39b 100644 --- a/lib/bigcommerce/api/customers/handlers/create-customer.ts +++ b/lib/bigcommerce/api/customers/handlers/signup.ts @@ -1,8 +1,8 @@ import { BigcommerceApiError } from '../../utils/errors' import login from '../../operations/login' -import type { CustomersHandlers } from '..' +import { SignupHandlers } from '../signup' -const createCustomer: CustomersHandlers['createCustomer'] = async ({ +const signup: SignupHandlers['signup'] = async ({ res, body: { firstName, lastName, email, password }, config, @@ -57,6 +57,7 @@ const createCustomer: CustomersHandlers['createCustomer'] = async ({ console.log('DATA', result.data) + // TODO: Currently not working, fix this asap. const loginData = await login({ variables: { email, password }, config }) console.log('LOGIN DATA', loginData) @@ -64,4 +65,4 @@ const createCustomer: CustomersHandlers['createCustomer'] = async ({ res.status(200).json({ data: result.data ?? null }) } -export default createCustomer +export default signup diff --git a/lib/bigcommerce/api/customers/index.ts b/lib/bigcommerce/api/customers/index.ts index c39f55f6a..228e882e7 100644 --- a/lib/bigcommerce/api/customers/index.ts +++ b/lib/bigcommerce/api/customers/index.ts @@ -4,42 +4,30 @@ import createApiHandler, { } from '../utils/create-api-handler' import isAllowedMethod from '../utils/is-allowed-method' import { BigcommerceApiError } from '../utils/errors' -import createCustomer from './handlers/create-customer' +import getLoggedInCustomer from './handlers/get-logged-in-customer' -type Body = Partial | undefined +export type Customer = any -export type Customer = null - -export type CreateCustomerBody = { - firstName: string - lastName: string - email: string - password: string +export type CustomerData = { + customer: Customer } export type CustomersHandlers = { - createCustomer: BigcommerceHandler< - Customer, - { cartId?: string } & Body - > + getLoggedInCustomer: BigcommerceHandler } -const METHODS = ['POST'] +const METHODS = ['GET'] -const customersApi: BigcommerceApiHandler = async ( - req, - res, - config -) => { +const customersApi: BigcommerceApiHandler< + CustomerData, + CustomersHandlers +> = async (req, res, config, handlers) => { if (!isAllowedMethod(req, res, METHODS)) return - const { cookies } = req - const cartId = cookies[config.cartCookie] - try { - if (req.method === 'POST') { - const body = { cartId, ...req.body } - return await handlers['createCustomer']({ req, res, config, body }) + if (req.method === 'GET') { + const body = null + return await handlers['getLoggedInCustomer']({ req, res, config, body }) } } catch (error) { console.error(error) @@ -53,6 +41,6 @@ const customersApi: BigcommerceApiHandler = async ( } } -const handlers = { createCustomer } +const handlers = { getLoggedInCustomer } export default createApiHandler(customersApi, handlers, {}) diff --git a/lib/bigcommerce/api/customers/login.ts b/lib/bigcommerce/api/customers/login.ts new file mode 100644 index 000000000..e8f24a92d --- /dev/null +++ b/lib/bigcommerce/api/customers/login.ts @@ -0,0 +1,45 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import login from './handlers/login' + +export type LoginBody = { + email: string + password: string +} + +export type LoginHandlers = { + login: BigcommerceHandler> +} + +const METHODS = ['POST'] + +const loginApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + try { + const body = req.body ?? {} + return await handlers['login']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { login } + +export default createApiHandler(loginApi, handlers, {}) diff --git a/lib/bigcommerce/api/customers/signup.ts b/lib/bigcommerce/api/customers/signup.ts new file mode 100644 index 000000000..aa26f78cf --- /dev/null +++ b/lib/bigcommerce/api/customers/signup.ts @@ -0,0 +1,50 @@ +import createApiHandler, { + BigcommerceApiHandler, + BigcommerceHandler, +} from '../utils/create-api-handler' +import isAllowedMethod from '../utils/is-allowed-method' +import { BigcommerceApiError } from '../utils/errors' +import signup from './handlers/signup' + +export type SignupBody = { + firstName: string + lastName: string + email: string + password: string +} + +export type SignupHandlers = { + signup: BigcommerceHandler> +} + +const METHODS = ['POST'] + +const signupApi: BigcommerceApiHandler = async ( + req, + res, + config, + handlers +) => { + if (!isAllowedMethod(req, res, METHODS)) return + + const { cookies } = req + const cartId = cookies[config.cartCookie] + + try { + const body = { ...req.body, cartId } + return await handlers['signup']({ req, res, config, body }) + } catch (error) { + console.error(error) + + const message = + error instanceof BigcommerceApiError + ? 'An unexpected error ocurred with the Bigcommerce API' + : 'An unexpected error ocurred' + + res.status(500).json({ data: null, errors: [{ message }] }) + } +} + +const handlers = { signup } + +export default createApiHandler(signupApi, handlers, {}) diff --git a/lib/bigcommerce/api/utils/create-api-handler.ts b/lib/bigcommerce/api/utils/create-api-handler.ts index c6363cb15..be623d4cd 100644 --- a/lib/bigcommerce/api/utils/create-api-handler.ts +++ b/lib/bigcommerce/api/utils/create-api-handler.ts @@ -3,7 +3,7 @@ import { BigcommerceConfig, getConfig } from '..' export type BigcommerceApiHandler< T = any, - H extends BigcommerceHandlers = {}, + H extends BigcommerceHandlers = {}, Options extends {} = {} > = ( req: NextApiRequest, diff --git a/lib/bigcommerce/api/wishlist/index.ts b/lib/bigcommerce/api/wishlist/index.ts index 912d59491..7ab8c9173 100644 --- a/lib/bigcommerce/api/wishlist/index.ts +++ b/lib/bigcommerce/api/wishlist/index.ts @@ -47,7 +47,7 @@ export type Wishlist = { export type WishlistList = Wishlist[] export type WishlistHandlers = { - getAllWishlists: BigcommerceHandler + getAllWishlists: BigcommerceHandler getWishlist: BigcommerceHandler addWishlist: BigcommerceHandler< Wishlist, @@ -57,7 +57,10 @@ export type WishlistHandlers = { Wishlist, { wishlistId: string } & Body > - addItem: BigcommerceHandler> + addItem: BigcommerceHandler< + Wishlist, + { wishlistId: string } & Body + > removeItem: BigcommerceHandler< Wishlist, { wishlistId: string } & Body @@ -86,13 +89,13 @@ const wishlistApi: BigcommerceApiHandler = async ( // Add an item to the wishlist if (req.method === 'POST' && wishlistId) { - const body = { wishlistId, ...req.body } + const body = { ...req.body, wishlistId } return await handlers['addItem']({ req, res, config, body }) } // Update a wishlist if (req.method === 'PUT' && wishlistId) { - const body = { wishlistId, ...req.body } + const body = { ...req.body, wishlistId } return await handlers['updateWishlist']({ req, res, config, body }) } diff --git a/lib/bigcommerce/cart/use-add-item.tsx b/lib/bigcommerce/cart/use-add-item.tsx index a18a7b651..fa8bb8b46 100644 --- a/lib/bigcommerce/cart/use-add-item.tsx +++ b/lib/bigcommerce/cart/use-add-item.tsx @@ -26,8 +26,8 @@ export const fetcher: HookFetcher = ( } return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { item }, }) } diff --git a/lib/bigcommerce/cart/use-cart.tsx b/lib/bigcommerce/cart/use-cart.tsx index 8fe80747a..7ed6ba7d8 100644 --- a/lib/bigcommerce/cart/use-cart.tsx +++ b/lib/bigcommerce/cart/use-cart.tsx @@ -5,6 +5,7 @@ import type { Cart } from '../api/cart' const defaultOpts = { url: '/api/bigcommerce/cart', + method: 'GET', } export type { Cart } @@ -14,12 +15,7 @@ export const fetcher: HookFetcher = ( { cartId }, fetch ) => { - return cartId - ? fetch({ - url: options?.url, - query: options?.query, - }) - : null + return cartId ? fetch({ ...defaultOpts, ...options }) : null } export function extendHook( diff --git a/lib/bigcommerce/cart/use-remove-item.tsx b/lib/bigcommerce/cart/use-remove-item.tsx index 386462c7f..c07aa718e 100644 --- a/lib/bigcommerce/cart/use-remove-item.tsx +++ b/lib/bigcommerce/cart/use-remove-item.tsx @@ -19,8 +19,8 @@ export const fetcher: HookFetcher = ( fetch ) => { return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { itemId }, }) } diff --git a/lib/bigcommerce/cart/use-update-item.tsx b/lib/bigcommerce/cart/use-update-item.tsx index 78dd1bb84..bcad7ab3a 100644 --- a/lib/bigcommerce/cart/use-update-item.tsx +++ b/lib/bigcommerce/cart/use-update-item.tsx @@ -28,8 +28,8 @@ export const fetcher: HookFetcher = ( } return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { itemId, item }, }) } diff --git a/lib/bigcommerce/schema.d.ts b/lib/bigcommerce/schema.d.ts index eae1c8187..361d45a30 100644 --- a/lib/bigcommerce/schema.d.ts +++ b/lib/bigcommerce/schema.d.ts @@ -1653,6 +1653,30 @@ export enum CurrencyCode { Zwr = 'ZWR', } +export type GetLoggedInCustomerQueryVariables = Exact<{ [key: string]: never }> + +export type GetLoggedInCustomerQuery = { __typename?: 'Query' } & { + customer?: Maybe< + { __typename?: 'Customer' } & Pick< + Customer, + | 'entityId' + | 'firstName' + | 'lastName' + | 'email' + | 'company' + | 'customerGroupId' + | 'notes' + | 'phone' + | 'addressCount' + | 'attributeCount' + > & { + storeCredit: Array< + { __typename?: 'Money' } & Pick + > + } + > +} + export type CategoryTreeItemFragment = { __typename?: 'CategoryTreeItem' } & Pick< diff --git a/lib/bigcommerce/use-customer.tsx b/lib/bigcommerce/use-customer.tsx new file mode 100644 index 000000000..549fd3fa1 --- /dev/null +++ b/lib/bigcommerce/use-customer.tsx @@ -0,0 +1,41 @@ +import { ConfigInterface } from 'swr' +import { HookFetcher } from '@lib/commerce/utils/types' +import useCommerceCustomer, { CustomerInput } from '@lib/commerce/use-customer' +import type { Customer, CustomerData } from './api/customers' + +const defaultOpts = { + url: '/api/bigcommerce/customer', + method: 'GET', +} + +export type { Customer } + +export const fetcher: HookFetcher = ( + options, + { cartId }, + fetch +) => { + return cartId ? fetch({ ...defaultOpts, ...options }) : null +} + +export function extendHook( + customFetcher: typeof fetcher, + swrOptions?: ConfigInterface +) { + const useCustomer = () => { + const cart = useCommerceCustomer( + defaultOpts, + [], + customFetcher, + { revalidateOnFocus: false, ...swrOptions } + ) + + return cart + } + + useCustomer.extend = extendHook + + return useCustomer +} + +export default extendHook(fetcher) diff --git a/lib/bigcommerce/use-login.tsx b/lib/bigcommerce/use-login.tsx new file mode 100644 index 000000000..d2b86a827 --- /dev/null +++ b/lib/bigcommerce/use-login.tsx @@ -0,0 +1,49 @@ +import { useCallback } from 'react' +import { HookFetcher } from '@lib/commerce/utils/types' +import useCommerceLogin from '@lib/commerce/use-login' +import type { LoginBody } from './api/customers/login' + +const defaultOpts = { + url: '/api/bigcommerce/customers/login', + method: 'POST', +} + +export type LoginInput = LoginBody + +export const fetcher: HookFetcher = ( + options, + { email, password }, + fetch +) => { + if (!(email && password)) { + throw new Error( + 'A first name, last name, email and password are required to login' + ) + } + + return fetch({ + ...defaultOpts, + ...options, + body: { email, password }, + }) +} + +export function extendHook(customFetcher: typeof fetcher) { + const useLogin = () => { + const fn = useCommerceLogin(defaultOpts, customFetcher) + + return useCallback( + async function login(input: LoginInput) { + const data = await fn(input) + return data + }, + [fn] + ) + } + + useLogin.extend = extendHook + + return useLogin +} + +export default extendHook(fetcher) diff --git a/lib/bigcommerce/use-signup.tsx b/lib/bigcommerce/use-signup.tsx new file mode 100644 index 000000000..68183aa6c --- /dev/null +++ b/lib/bigcommerce/use-signup.tsx @@ -0,0 +1,49 @@ +import { useCallback } from 'react' +import { HookFetcher } from '@lib/commerce/utils/types' +import useCommerceSignup from '@lib/commerce/use-signup' +import type { SignupBody } from './api/customers/signup' + +const defaultOpts = { + url: '/api/bigcommerce/customers/signup', + method: 'POST', +} + +export type SignupInput = SignupBody + +export const fetcher: HookFetcher = ( + options, + { firstName, lastName, email, password }, + fetch +) => { + if (!(firstName && lastName && email && password)) { + throw new Error( + 'A first name, last name, email and password are required to signup' + ) + } + + return fetch({ + ...defaultOpts, + ...options, + body: { firstName, lastName, email, password }, + }) +} + +export function extendHook(customFetcher: typeof fetcher) { + const useSignup = () => { + const fn = useCommerceSignup(defaultOpts, customFetcher) + + return useCallback( + async function signup(input: SignupInput) { + const data = await fn(input) + return data + }, + [fn] + ) + } + + useSignup.extend = extendHook + + return useSignup +} + +export default extendHook(fetcher) diff --git a/lib/bigcommerce/wishlist/use-add-item.tsx b/lib/bigcommerce/wishlist/use-add-item.tsx index 862041bbd..9bbbe009e 100644 --- a/lib/bigcommerce/wishlist/use-add-item.tsx +++ b/lib/bigcommerce/wishlist/use-add-item.tsx @@ -17,8 +17,8 @@ export const fetcher: HookFetcher = ( fetch ) => { return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { wishlistId, item }, }) } diff --git a/lib/bigcommerce/wishlist/use-remove-item.tsx b/lib/bigcommerce/wishlist/use-remove-item.tsx index ca9648d35..05f9744cb 100644 --- a/lib/bigcommerce/wishlist/use-remove-item.tsx +++ b/lib/bigcommerce/wishlist/use-remove-item.tsx @@ -19,8 +19,8 @@ export const fetcher: HookFetcher = ( fetch ) => { return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { wishlistId, itemId }, }) } diff --git a/lib/bigcommerce/wishlist/use-wishlist.tsx b/lib/bigcommerce/wishlist/use-wishlist.tsx index 1d93609f0..d60660c05 100644 --- a/lib/bigcommerce/wishlist/use-wishlist.tsx +++ b/lib/bigcommerce/wishlist/use-wishlist.tsx @@ -4,6 +4,7 @@ import type { Wishlist } from '../api/wishlist' const defaultOpts = { url: '/api/bigcommerce/wishlists', + method: 'GET', } export type { Wishlist } @@ -18,7 +19,8 @@ export const fetcher: HookFetcher = ( fetch ) => { return fetch({ - url: options?.url, + ...defaultOpts, + ...options, body: { wishlistId }, }) } diff --git a/lib/commerce/api/index.ts b/lib/commerce/api/index.ts index 6c4bf0544..38ed70d4a 100644 --- a/lib/commerce/api/index.ts +++ b/lib/commerce/api/index.ts @@ -14,8 +14,4 @@ export interface CommerceAPIFetchOptions { preview?: boolean } -// TODO: define interfaces for all the available operations - -// export interface CommerceAPI { -// getAllProducts(options?: { query: string }): Promise; -// } +// TODO: define interfaces for all the available operations and API endpoints diff --git a/lib/commerce/use-customer.tsx b/lib/commerce/use-customer.tsx new file mode 100644 index 000000000..e33587dcf --- /dev/null +++ b/lib/commerce/use-customer.tsx @@ -0,0 +1,30 @@ +import { responseInterface, ConfigInterface } from 'swr' +import Cookies from 'js-cookie' +import type { HookInput, HookFetcher, HookFetcherOptions } from './utils/types' +import useData from './utils/use-data' +import { useCommerce } from '.' + +export type CustomerResponse = responseInterface + +export type CustomerInput = { + cartId: string | undefined +} + +export default function useCustomer( + options: HookFetcherOptions, + input: HookInput, + fetcherFn: HookFetcher, + swrOptions?: ConfigInterface +) { + // TODO: Replace this with the login cookie + const { cartCookie } = useCommerce() + + const fetcher: typeof fetcherFn = (options, input, fetch) => { + input.cartId = Cookies.get(cartCookie) + return fetcherFn(options, input, fetch) + } + + const response = useData(options, input, fetcher, swrOptions) + + return response as CustomerResponse +} diff --git a/lib/commerce/use-login.tsx b/lib/commerce/use-login.tsx new file mode 100644 index 000000000..2a251fea3 --- /dev/null +++ b/lib/commerce/use-login.tsx @@ -0,0 +1,5 @@ +import useAction from './utils/use-action' + +const useLogin = useAction + +export default useLogin diff --git a/lib/commerce/use-signup.tsx b/lib/commerce/use-signup.tsx new file mode 100644 index 000000000..08ddb22c0 --- /dev/null +++ b/lib/commerce/use-signup.tsx @@ -0,0 +1,5 @@ +import useAction from './utils/use-action' + +const useSignup = useAction + +export default useSignup diff --git a/lib/commerce/utils/use-action.tsx b/lib/commerce/utils/use-action.tsx index ef68a7641..e60cae06b 100644 --- a/lib/commerce/utils/use-action.tsx +++ b/lib/commerce/utils/use-action.tsx @@ -9,9 +9,7 @@ export default function useAction( const { fetcherRef } = useCommerce() return useCallback( - function addItem(input: Input) { - return fetcher(options, input, fetcherRef.current) - }, + (input: Input) => fetcher(options, input, fetcherRef.current), [fetcher] ) } diff --git a/lib/commerce/utils/use-data.tsx b/lib/commerce/utils/use-data.tsx index fa2b6175c..c8e31657f 100644 --- a/lib/commerce/utils/use-data.tsx +++ b/lib/commerce/utils/use-data.tsx @@ -9,9 +9,15 @@ export default function useData( swrOptions?: ConfigInterface ) { const { fetcherRef } = useCommerce() - const fetcher = (url?: string, query?: string, ...args: any[]) => { + const fetcher = ( + url?: string, + query?: string, + method?: string, + ...args: any[] + ) => { return fetcherFn( - { url, query }, + { url, query, method }, + // Transform the input array into an object args.reduce((obj, val, i) => { obj[input[i][0]!] = val return obj @@ -23,7 +29,9 @@ export default function useData( const response = useSWR( () => { const opts = typeof options === 'function' ? options() : options - return opts ? [opts.url, opts.query, ...input.map((e) => e[1])] : null + return opts + ? [opts.url, opts.query, opts.method, ...input.map((e) => e[1])] + : null }, fetcher, swrOptions diff --git a/pages/api/bigcommerce/customers.ts b/pages/api/bigcommerce/customers/index.ts similarity index 100% rename from pages/api/bigcommerce/customers.ts rename to pages/api/bigcommerce/customers/index.ts diff --git a/pages/api/bigcommerce/customers/login.ts b/pages/api/bigcommerce/customers/login.ts new file mode 100644 index 000000000..b64b2252a --- /dev/null +++ b/pages/api/bigcommerce/customers/login.ts @@ -0,0 +1,3 @@ +import loginApi from '@lib/bigcommerce/api/customers/login' + +export default loginApi() diff --git a/pages/api/bigcommerce/customers/signup.ts b/pages/api/bigcommerce/customers/signup.ts new file mode 100644 index 000000000..d8be5512f --- /dev/null +++ b/pages/api/bigcommerce/customers/signup.ts @@ -0,0 +1,3 @@ +import signupApi from '@lib/bigcommerce/api/customers/signup' + +export default signupApi()