diff --git a/lib/bigcommerce/api/cart/handlers/get-cart.ts b/lib/bigcommerce/api/cart/handlers/get-cart.ts index 212107c5a..9fb42d730 100644 --- a/lib/bigcommerce/api/cart/handlers/get-cart.ts +++ b/lib/bigcommerce/api/cart/handlers/get-cart.ts @@ -10,14 +10,16 @@ const getCart: CartHandlers['getCart'] = async ({ }) => { let result: { data?: Cart } = {} - try { - result = await config.storeApiFetch(`/v3/carts/${cartId}`) - } catch (error) { - if (error instanceof BigcommerceApiError && error.status === 404) { - // Remove the cookie if it exists but the cart wasn't found - res.setHeader('Set-Cookie', getCartCookie(config.cartCookie)) - } else { - throw error + if (cartId) { + try { + result = await config.storeApiFetch(`/v3/carts/${cartId}`) + } catch (error) { + if (error instanceof BigcommerceApiError && error.status === 404) { + // Remove the cookie if it exists but the cart wasn't found + res.setHeader('Set-Cookie', getCartCookie(config.cartCookie)) + } else { + throw 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 index 6ed97bec3..170457f59 100644 --- a/lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts +++ b/lib/bigcommerce/api/customers/handlers/get-logged-in-customer.ts @@ -1,4 +1,4 @@ -import { GetLoggedInCustomerQuery } from '@lib/bigcommerce/schema' +import type { GetLoggedInCustomerQuery } from '@lib/bigcommerce/schema' import type { CustomersHandlers } from '..' export const getLoggedInCustomerQuery = /* GraphQL */ ` @@ -22,23 +22,40 @@ export const getLoggedInCustomerQuery = /* GraphQL */ ` } ` +export type Customer = NonNullable + const getLoggedInCustomer: CustomersHandlers['getLoggedInCustomer'] = async ({ + req, res, config, }) => { - const { data } = await config.fetch( - getLoggedInCustomerQuery - ) - const { customer } = data + const token = req.cookies[config.customerCookie] - if (!customer) { - return res.status(400).json({ - data: null, - errors: [{ message: 'Customer not found', code: 'not_found' }], - }) + if (token) { + const { data } = await config.fetch( + getLoggedInCustomerQuery, + undefined, + { + headers: { + cookie: `${config.customerCookie}=${token}`, + }, + } + ) + const { customer } = data + + console.log('CUSTOMER', customer) + + if (!customer) { + return res.status(400).json({ + data: null, + errors: [{ message: 'Customer not found', code: 'not_found' }], + }) + } + + return res.status(200).json({ data: { customer } }) } - res.status(200).json({ data: { customer } }) + res.status(200).json({ data: null }) } export default getLoggedInCustomer diff --git a/lib/bigcommerce/api/customers/index.ts b/lib/bigcommerce/api/customers/index.ts index 228e882e7..5af4d1d1d 100644 --- a/lib/bigcommerce/api/customers/index.ts +++ b/lib/bigcommerce/api/customers/index.ts @@ -4,16 +4,18 @@ import createApiHandler, { } from '../utils/create-api-handler' import isAllowedMethod from '../utils/is-allowed-method' import { BigcommerceApiError } from '../utils/errors' -import getLoggedInCustomer from './handlers/get-logged-in-customer' +import getLoggedInCustomer, { + Customer, +} from './handlers/get-logged-in-customer' -export type Customer = any +export type { Customer } export type CustomerData = { customer: Customer } export type CustomersHandlers = { - getLoggedInCustomer: BigcommerceHandler + getLoggedInCustomer: BigcommerceHandler } const METHODS = ['GET'] @@ -25,10 +27,8 @@ const customersApi: BigcommerceApiHandler< if (!isAllowedMethod(req, res, METHODS)) return try { - if (req.method === 'GET') { - const body = null - return await handlers['getLoggedInCustomer']({ req, res, config, body }) - } + const body = null + return await handlers['getLoggedInCustomer']({ req, res, config, body }) } catch (error) { console.error(error) diff --git a/lib/bigcommerce/use-customer.tsx b/lib/bigcommerce/use-customer.tsx index 549fd3fa1..85266fbd0 100644 --- a/lib/bigcommerce/use-customer.tsx +++ b/lib/bigcommerce/use-customer.tsx @@ -1,36 +1,33 @@ -import { ConfigInterface } from 'swr' import { HookFetcher } from '@lib/commerce/utils/types' -import useCommerceCustomer, { CustomerInput } from '@lib/commerce/use-customer' +import type { SwrOptions } from '@lib/commerce/utils/use-data' +import useCommerceCustomer from '@lib/commerce/use-customer' import type { Customer, CustomerData } from './api/customers' const defaultOpts = { - url: '/api/bigcommerce/customer', + url: '/api/bigcommerce/customers', method: 'GET', } export type { Customer } -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = async ( options, - { cartId }, + _, fetch ) => { - return cartId ? fetch({ ...defaultOpts, ...options }) : null + const data = await fetch({ ...defaultOpts, ...options }) + return data.customer } export function extendHook( customFetcher: typeof fetcher, - swrOptions?: ConfigInterface + swrOptions?: SwrOptions ) { const useCustomer = () => { - const cart = useCommerceCustomer( - defaultOpts, - [], - customFetcher, - { revalidateOnFocus: false, ...swrOptions } - ) - - return cart + return useCommerceCustomer(defaultOpts, [], customFetcher, { + revalidateOnFocus: false, + ...swrOptions, + }) } useCustomer.extend = extendHook diff --git a/lib/commerce/cart/use-cart.tsx b/lib/commerce/cart/use-cart.tsx index 18afba7ba..f23103156 100644 --- a/lib/commerce/cart/use-cart.tsx +++ b/lib/commerce/cart/use-cart.tsx @@ -1,4 +1,4 @@ -import { responseInterface, ConfigInterface } from 'swr' +import type { responseInterface, ConfigInterface } from 'swr' import Cookies from 'js-cookie' import type { HookInput, HookFetcher, HookFetcherOptions } from '../utils/types' import useData from '../utils/use-data' diff --git a/lib/commerce/use-customer.tsx b/lib/commerce/use-customer.tsx index e33587dcf..8e2ff3ec2 100644 --- a/lib/commerce/use-customer.tsx +++ b/lib/commerce/use-customer.tsx @@ -1,30 +1,5 @@ -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 +const useCustomer = useData -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 -} +export default useCustomer diff --git a/lib/commerce/utils/types.ts b/lib/commerce/utils/types.ts index 81f05da3e..5fd18d46d 100644 --- a/lib/commerce/utils/types.ts +++ b/lib/commerce/utils/types.ts @@ -9,11 +9,11 @@ export type FetcherOptions = { body?: any } -export type HookFetcher = ( +export type HookFetcher = ( options: HookFetcherOptions | null, input: Input, - fetch: Fetcher -) => T | Promise + fetch: (options: FetcherOptions) => Promise +) => Result | Promise export type HookFetcherOptions = { query?: string diff --git a/lib/commerce/utils/use-data.tsx b/lib/commerce/utils/use-data.tsx index c8e31657f..7d94b408b 100644 --- a/lib/commerce/utils/use-data.tsx +++ b/lib/commerce/utils/use-data.tsx @@ -1,13 +1,22 @@ -import useSWR, { ConfigInterface } from 'swr' +import useSWR, { ConfigInterface, responseInterface } from 'swr' import type { HookInput, HookFetcher, HookFetcherOptions } from './types' +import { CommerceError } from './errors' import { useCommerce } from '..' -export default function useData( +export type SwrOptions = ConfigInterface< + Result, + CommerceError, + HookFetcher +> + +export type UseData = ( options: HookFetcherOptions | (() => HookFetcherOptions | null), input: HookInput, - fetcherFn: HookFetcher, - swrOptions?: ConfigInterface -) { + fetcherFn: HookFetcher, + swrOptions?: SwrOptions +) => responseInterface + +const useData: UseData = (options, input, fetcherFn, swrOptions) => { const { fetcherRef } = useCommerce() const fetcher = ( url?: string, @@ -25,7 +34,6 @@ export default function useData( fetcherRef.current ) } - const response = useSWR( () => { const opts = typeof options === 'function' ? options() : options @@ -39,3 +47,5 @@ export default function useData( return response } + +export default useData diff --git a/pages/login.tsx b/pages/login.tsx index ae92455fd..fd6e12687 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -3,11 +3,15 @@ import { Layout } from '@components/core' import { Logo, Modal, Button } from '@components/ui' import useLogin from '@lib/bigcommerce/use-login' import useLogout from '@lib/bigcommerce/use-logout' +import useCustomer from '@lib/bigcommerce/use-customer' export default function Login() { const signup = useSignup() const login = useLogin() const logout = useLogout() + // Data about the currently logged in customer, it will update + // automatically after a signup/login/logout + const { data } = useCustomer() // TODO: use this method. It can take more than 5 seconds to do a signup const handleSignup = async () => { // TODO: validate the password and email before calling the signup