From ef81a968af977ec2b32698f86bfc513a8862c617 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Tue, 20 Oct 2020 13:49:17 -0500 Subject: [PATCH 1/8] Fix potential body bug --- lib/bigcommerce/api/cart/index.ts | 6 +++--- lib/bigcommerce/api/customers/index.ts | 2 +- lib/bigcommerce/api/wishlist/index.ts | 11 +++++++---- lib/commerce/api/index.ts | 6 +----- 4 files changed, 12 insertions(+), 13 deletions(-) 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/index.ts b/lib/bigcommerce/api/customers/index.ts index c39f55f6a..a626ef2c7 100644 --- a/lib/bigcommerce/api/customers/index.ts +++ b/lib/bigcommerce/api/customers/index.ts @@ -38,7 +38,7 @@ const customersApi: BigcommerceApiHandler = async ( try { if (req.method === 'POST') { - const body = { cartId, ...req.body } + const body = { ...req.body, cartId } return await handlers['createCustomer']({ req, res, config, body }) } } catch (error) { 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/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 From e2b26715b9b8309a5012a92efda4f966d1434504 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Tue, 20 Oct 2020 13:49:37 -0500 Subject: [PATCH 2/8] use-signup --- lib/bigcommerce/use-signup.tsx | 52 +++++++++++++++++++++++++++++++ lib/commerce/use-signup.tsx | 5 +++ lib/commerce/utils/use-action.tsx | 4 +-- 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 lib/bigcommerce/use-signup.tsx create mode 100644 lib/commerce/use-signup.tsx diff --git a/lib/bigcommerce/use-signup.tsx b/lib/bigcommerce/use-signup.tsx new file mode 100644 index 000000000..699f0d9b1 --- /dev/null +++ b/lib/bigcommerce/use-signup.tsx @@ -0,0 +1,52 @@ +import { useCallback } from 'react' +import { HookFetcher } from '@lib/commerce/utils/types' +import useCommerceSignup from '@lib/commerce/use-signup' +import type { CreateCustomerBody } from './api/customers' + +const defaultOpts = { + url: '/api/bigcommerce/customers', + method: 'POST', +} + +export type SignupInput = CreateCustomerBody + +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({ + url: options?.url ?? defaultOpts.url, + method: options?.method ?? defaultOpts.method, + 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/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] ) } From a1e47a73d2ea0e305fb6c04cd6d6855027ab1e95 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Tue, 20 Oct 2020 22:27:38 -0500 Subject: [PATCH 3/8] Added useLogin hook and API endpoint --- .../api/customers/handlers/create-customer.ts | 1 + .../api/customers/handlers/login.ts | 26 ++++++++++ lib/bigcommerce/api/customers/login.ts | 45 +++++++++++++++++ .../api/utils/create-api-handler.ts | 2 +- lib/bigcommerce/use-login.tsx | 49 +++++++++++++++++++ lib/bigcommerce/use-signup.tsx | 7 +-- lib/commerce/use-login.tsx | 5 ++ .../{customers.ts => customers/index.ts} | 0 pages/api/bigcommerce/customers/login.ts | 3 ++ 9 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 lib/bigcommerce/api/customers/handlers/login.ts create mode 100644 lib/bigcommerce/api/customers/login.ts create mode 100644 lib/bigcommerce/use-login.tsx create mode 100644 lib/commerce/use-login.tsx rename pages/api/bigcommerce/{customers.ts => customers/index.ts} (100%) create mode 100644 pages/api/bigcommerce/customers/login.ts diff --git a/lib/bigcommerce/api/customers/handlers/create-customer.ts b/lib/bigcommerce/api/customers/handlers/create-customer.ts index a666467ab..4ccbf31b4 100644 --- a/lib/bigcommerce/api/customers/handlers/create-customer.ts +++ b/lib/bigcommerce/api/customers/handlers/create-customer.ts @@ -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) 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/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/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/use-login.tsx b/lib/bigcommerce/use-login.tsx new file mode 100644 index 000000000..37d59a79c --- /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({ + url: options?.url ?? defaultOpts.url, + method: options?.method ?? defaultOpts.method, + 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 index 699f0d9b1..5f7338d6e 100644 --- a/lib/bigcommerce/use-signup.tsx +++ b/lib/bigcommerce/use-signup.tsx @@ -10,7 +10,7 @@ const defaultOpts = { export type SignupInput = CreateCustomerBody -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, { firstName, lastName, email, password }, fetch @@ -30,10 +30,7 @@ export const fetcher: HookFetcher = ( export function extendHook(customFetcher: typeof fetcher) { const useSignup = () => { - const fn = useCommerceSignup( - defaultOpts, - customFetcher - ) + const fn = useCommerceSignup(defaultOpts, customFetcher) return useCallback( async function signup(input: SignupInput) { 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/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() From f0a2c744e83daa8e6cb9cc793ffd5d91330b22e7 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 21 Oct 2020 09:15:14 -0500 Subject: [PATCH 4/8] Moved create customer API to signup method --- .../api/customers/handlers/signup.ts | 68 +++++++++++++++++++ lib/bigcommerce/api/customers/signup.ts | 50 ++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 lib/bigcommerce/api/customers/handlers/signup.ts create mode 100644 lib/bigcommerce/api/customers/signup.ts diff --git a/lib/bigcommerce/api/customers/handlers/signup.ts b/lib/bigcommerce/api/customers/handlers/signup.ts new file mode 100644 index 000000000..85400e39b --- /dev/null +++ b/lib/bigcommerce/api/customers/handlers/signup.ts @@ -0,0 +1,68 @@ +import { BigcommerceApiError } from '../../utils/errors' +import login from '../../operations/login' +import { SignupHandlers } from '../signup' + +const signup: SignupHandlers['signup'] = async ({ + res, + body: { firstName, lastName, email, password }, + config, +}) => { + // TODO: Add proper validations with something like Ajv + if (!(firstName && lastName && 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. + + let result: { data?: any } = {} + + try { + result = await config.storeApiFetch('/v3/customers', { + method: 'POST', + body: JSON.stringify([ + { + first_name: firstName, + last_name: lastName, + email, + authentication: { + new_password: password, + }, + }, + ]), + }) + } catch (error) { + if (error instanceof BigcommerceApiError && error.status === 422) { + const hasEmailError = '0.email' in error.data?.errors + + // If there's an error with the email, it most likely means it's duplicated + if (hasEmailError) { + return res.status(400).json({ + data: null, + errors: [ + { + message: 'The email is already in use', + code: 'duplicated_email', + }, + ], + }) + } + } + + throw error + } + + 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) + + res.status(200).json({ data: result.data ?? null }) +} + +export default signup 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, {}) From 377015ceac2a082c9b8bed2375d91f0a7ab713a5 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 21 Oct 2020 09:17:52 -0500 Subject: [PATCH 5/8] updated useSignup hook --- lib/bigcommerce/use-signup.tsx | 8 ++++---- pages/api/bigcommerce/customers/signup.ts | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 pages/api/bigcommerce/customers/signup.ts diff --git a/lib/bigcommerce/use-signup.tsx b/lib/bigcommerce/use-signup.tsx index 5f7338d6e..e97594864 100644 --- a/lib/bigcommerce/use-signup.tsx +++ b/lib/bigcommerce/use-signup.tsx @@ -1,16 +1,16 @@ import { useCallback } from 'react' import { HookFetcher } from '@lib/commerce/utils/types' import useCommerceSignup from '@lib/commerce/use-signup' -import type { CreateCustomerBody } from './api/customers' +import type { SignupBody } from './api/customers/signup' const defaultOpts = { - url: '/api/bigcommerce/customers', + url: '/api/bigcommerce/customers/signup', method: 'POST', } -export type SignupInput = CreateCustomerBody +export type SignupInput = SignupBody -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, { firstName, lastName, email, password }, fetch 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() From 2aae613f1b01b16a29c356ccf5819c3dc0a969c2 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 21 Oct 2020 09:53:19 -0500 Subject: [PATCH 6/8] Added op to get the logged in customer --- codegen.json | 2 +- .../api/customers/handlers/create-customer.ts | 68 ------------------- .../handlers/get-logged-in-customer.ts | 44 ++++++++++++ lib/bigcommerce/api/customers/index.ts | 40 ++++------- lib/bigcommerce/schema.d.ts | 24 +++++++ 5 files changed, 83 insertions(+), 95 deletions(-) delete mode 100644 lib/bigcommerce/api/customers/handlers/create-customer.ts create mode 100644 lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts 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/customers/handlers/create-customer.ts b/lib/bigcommerce/api/customers/handlers/create-customer.ts deleted file mode 100644 index 4ccbf31b4..000000000 --- a/lib/bigcommerce/api/customers/handlers/create-customer.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { BigcommerceApiError } from '../../utils/errors' -import login from '../../operations/login' -import type { CustomersHandlers } from '..' - -const createCustomer: CustomersHandlers['createCustomer'] = async ({ - res, - body: { firstName, lastName, email, password }, - config, -}) => { - // TODO: Add proper validations with something like Ajv - if (!(firstName && lastName && 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. - - let result: { data?: any } = {} - - try { - result = await config.storeApiFetch('/v3/customers', { - method: 'POST', - body: JSON.stringify([ - { - first_name: firstName, - last_name: lastName, - email, - authentication: { - new_password: password, - }, - }, - ]), - }) - } catch (error) { - if (error instanceof BigcommerceApiError && error.status === 422) { - const hasEmailError = '0.email' in error.data?.errors - - // If there's an error with the email, it most likely means it's duplicated - if (hasEmailError) { - return res.status(400).json({ - data: null, - errors: [ - { - message: 'The email is already in use', - code: 'duplicated_email', - }, - ], - }) - } - } - - throw error - } - - 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) - - res.status(200).json({ data: result.data ?? null }) -} - -export default createCustomer 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/index.ts b/lib/bigcommerce/api/customers/index.ts index a626ef2c7..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 = { ...req.body, cartId } - 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/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< From d98897a7e353db5e349dffefd0a064f08f62e485 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 21 Oct 2020 10:23:05 -0500 Subject: [PATCH 7/8] Added useCustomer hook --- lib/bigcommerce/cart/use-cart.tsx | 7 +----- lib/bigcommerce/use-customer.tsx | 40 +++++++++++++++++++++++++++++++ lib/commerce/use-customer.tsx | 30 +++++++++++++++++++++++ lib/commerce/utils/use-data.tsx | 1 + 4 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 lib/bigcommerce/use-customer.tsx create mode 100644 lib/commerce/use-customer.tsx diff --git a/lib/bigcommerce/cart/use-cart.tsx b/lib/bigcommerce/cart/use-cart.tsx index 8fe80747a..38d1d8bac 100644 --- a/lib/bigcommerce/cart/use-cart.tsx +++ b/lib/bigcommerce/cart/use-cart.tsx @@ -14,12 +14,7 @@ export const fetcher: HookFetcher = ( { cartId }, fetch ) => { - return cartId - ? fetch({ - url: options?.url, - query: options?.query, - }) - : null + return cartId ? fetch({ ...options }) : null } export function extendHook( diff --git a/lib/bigcommerce/use-customer.tsx b/lib/bigcommerce/use-customer.tsx new file mode 100644 index 000000000..273e4c871 --- /dev/null +++ b/lib/bigcommerce/use-customer.tsx @@ -0,0 +1,40 @@ +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', +} + +export type { Customer } + +export const fetcher: HookFetcher = ( + options, + { cartId }, + fetch +) => { + return cartId ? fetch({ ...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/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/utils/use-data.tsx b/lib/commerce/utils/use-data.tsx index fa2b6175c..513bec7bc 100644 --- a/lib/commerce/utils/use-data.tsx +++ b/lib/commerce/utils/use-data.tsx @@ -12,6 +12,7 @@ export default function useData( const fetcher = (url?: string, query?: string, ...args: any[]) => { return fetcherFn( { url, query }, + // Transform the input array into an object args.reduce((obj, val, i) => { obj[input[i][0]!] = val return obj From 2804627aefdd752923ca721d31717627a277f5b6 Mon Sep 17 00:00:00 2001 From: Luis Alvarez Date: Wed, 21 Oct 2020 10:35:49 -0500 Subject: [PATCH 8/8] Updated defaults in all hooks --- lib/bigcommerce/cart/use-add-item.tsx | 4 ++-- lib/bigcommerce/cart/use-cart.tsx | 3 ++- lib/bigcommerce/cart/use-remove-item.tsx | 4 ++-- lib/bigcommerce/cart/use-update-item.tsx | 4 ++-- lib/bigcommerce/use-customer.tsx | 3 ++- lib/bigcommerce/use-login.tsx | 4 ++-- lib/bigcommerce/use-signup.tsx | 4 ++-- lib/bigcommerce/wishlist/use-add-item.tsx | 4 ++-- lib/bigcommerce/wishlist/use-remove-item.tsx | 4 ++-- lib/bigcommerce/wishlist/use-wishlist.tsx | 4 +++- lib/commerce/utils/use-data.tsx | 13 ++++++++++--- 11 files changed, 31 insertions(+), 20 deletions(-) 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 38d1d8bac..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,7 +15,7 @@ export const fetcher: HookFetcher = ( { cartId }, fetch ) => { - return cartId ? fetch({ ...options }) : 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/use-customer.tsx b/lib/bigcommerce/use-customer.tsx index 273e4c871..549fd3fa1 100644 --- a/lib/bigcommerce/use-customer.tsx +++ b/lib/bigcommerce/use-customer.tsx @@ -5,6 +5,7 @@ import type { Customer, CustomerData } from './api/customers' const defaultOpts = { url: '/api/bigcommerce/customer', + method: 'GET', } export type { Customer } @@ -14,7 +15,7 @@ export const fetcher: HookFetcher = ( { cartId }, fetch ) => { - return cartId ? fetch({ ...options }) : null + return cartId ? fetch({ ...defaultOpts, ...options }) : null } export function extendHook( diff --git a/lib/bigcommerce/use-login.tsx b/lib/bigcommerce/use-login.tsx index 37d59a79c..d2b86a827 100644 --- a/lib/bigcommerce/use-login.tsx +++ b/lib/bigcommerce/use-login.tsx @@ -22,8 +22,8 @@ export const fetcher: HookFetcher = ( } return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { email, password }, }) } diff --git a/lib/bigcommerce/use-signup.tsx b/lib/bigcommerce/use-signup.tsx index e97594864..68183aa6c 100644 --- a/lib/bigcommerce/use-signup.tsx +++ b/lib/bigcommerce/use-signup.tsx @@ -22,8 +22,8 @@ export const fetcher: HookFetcher = ( } return fetch({ - url: options?.url ?? defaultOpts.url, - method: options?.method ?? defaultOpts.method, + ...defaultOpts, + ...options, body: { firstName, lastName, email, password }, }) } 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/utils/use-data.tsx b/lib/commerce/utils/use-data.tsx index 513bec7bc..c8e31657f 100644 --- a/lib/commerce/utils/use-data.tsx +++ b/lib/commerce/utils/use-data.tsx @@ -9,9 +9,14 @@ 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 @@ -24,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