From eb7286f8e33e8ae2fadcbe533528691aa34fc607 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Mon, 25 Jan 2021 20:28:09 +0100 Subject: [PATCH] Implement auth/customer hooks --- .../vendure/api/utils/fetch-graphql-api.ts | 1 - framework/vendure/auth/login.ts | 2 +- framework/vendure/auth/use-login.tsx | 39 +++++++++------ framework/vendure/auth/use-logout.tsx | 22 +++++---- framework/vendure/auth/use-signup.tsx | 44 ++++++++++++----- framework/vendure/cart/use-cart.tsx | 2 +- framework/vendure/customer/use-customer.tsx | 39 ++++++++++----- framework/vendure/schema.d.ts | 49 +++++++++++++++++-- 8 files changed, 140 insertions(+), 58 deletions(-) diff --git a/framework/vendure/api/utils/fetch-graphql-api.ts b/framework/vendure/api/utils/fetch-graphql-api.ts index 63c573840..f769123e4 100644 --- a/framework/vendure/api/utils/fetch-graphql-api.ts +++ b/framework/vendure/api/utils/fetch-graphql-api.ts @@ -8,7 +8,6 @@ const fetchGraphqlApi: GraphQLFetcher = async ( { variables, preview } = {}, fetchOptions ) => { - // log.warn(query) const config = getConfig() const res = await fetch(config.commerceUrl, { ...fetchOptions, diff --git a/framework/vendure/auth/login.ts b/framework/vendure/auth/login.ts index ab2c0db00..26b9a66c1 100644 --- a/framework/vendure/auth/login.ts +++ b/framework/vendure/auth/login.ts @@ -5,7 +5,7 @@ import concatHeader from '../api/utils/concat-cookie' import { VendureConfig, getConfig } from '../api' export const loginMutation = /* GraphQL */ ` - mutation login($email: String!, $password: String!) { + mutation loginServer($email: String!, $password: String!) { login(username: $email, password: $password) { ...on CurrentUser { id diff --git a/framework/vendure/auth/use-login.tsx b/framework/vendure/auth/use-login.tsx index fa2294666..95be6103f 100644 --- a/framework/vendure/auth/use-login.tsx +++ b/framework/vendure/auth/use-login.tsx @@ -2,43 +2,50 @@ import { useCallback } from 'react' import type { HookFetcher } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useCommerceLogin from '@commerce/use-login' -import type { LoginBody } from '../api/customers/login' import useCustomer from '../customer/use-customer' +import { LoginMutation, LoginMutationVariables } from '@framework/schema' -const defaultOpts = { - url: '/api/bigcommerce/customers/login', - method: 'POST', -} +export const loginMutation = /* GraphQL */ ` + mutation login($username: String! $password: String!) { + login(username: $username, password: $password) { + __typename + ... on CurrentUser { + id + } + } + } +` -export type LoginInput = LoginBody - -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, - { email, password }, + { username, password }, fetch ) => { - if (!(email && password)) { + if (!(username && password)) { throw new CommerceError({ message: - 'A first name, last name, email and password are required to login', + 'An email address and password are required to login' }) } return fetch({ - ...defaultOpts, ...options, - body: { email, password }, + query: loginMutation, + variables: { username, password } }) } export function extendHook(customFetcher: typeof fetcher) { const useLogin = () => { const { revalidate } = useCustomer() - const fn = useCommerceLogin(defaultOpts, customFetcher) + const fn = useCommerceLogin({}, customFetcher) return useCallback( - async function login(input: LoginInput) { - const data = await fn(input) + async function login(input: { email: string; password: string; }) { + const data = await fn({ username: input.email, password: input.password }) + if (data.login.__typename !== 'CurrentUser') { + throw new CommerceError({ message: 'The credentials are not valid' }); + } await revalidate() return data }, diff --git a/framework/vendure/auth/use-logout.tsx b/framework/vendure/auth/use-logout.tsx index 6aaee29f9..d3188f0e3 100644 --- a/framework/vendure/auth/use-logout.tsx +++ b/framework/vendure/auth/use-logout.tsx @@ -2,28 +2,32 @@ import { useCallback } from 'react' import type { HookFetcher } from '@commerce/utils/types' import useCommerceLogout from '@commerce/use-logout' import useCustomer from '../customer/use-customer' +import { LogoutMutation } from '@framework/schema' -const defaultOpts = { - url: '/api/bigcommerce/customers/logout', - method: 'GET', -} +export const logoutMutation = /* GraphQL */` + mutation logout { + logout { + success + } + } +`; -export const fetcher: HookFetcher = (options, _, fetch) => { +export const fetcher: HookFetcher = (options, _, fetch) => { return fetch({ - ...defaultOpts, ...options, + query: logoutMutation }) } export function extendHook(customFetcher: typeof fetcher) { const useLogout = () => { const { mutate } = useCustomer() - const fn = useCommerceLogout(defaultOpts, customFetcher) + const fn = useCommerceLogout({}, customFetcher) return useCallback( - async function login() { + async function logout() { const data = await fn(null) - await mutate(null, false) + await mutate(null as any, false) return data }, [fn] diff --git a/framework/vendure/auth/use-signup.tsx b/framework/vendure/auth/use-signup.tsx index c68ce7b7a..54686b925 100644 --- a/framework/vendure/auth/use-signup.tsx +++ b/framework/vendure/auth/use-signup.tsx @@ -2,22 +2,33 @@ import { useCallback } from 'react' import type { HookFetcher } from '@commerce/utils/types' import { CommerceError } from '@commerce/utils/errors' import useCommerceSignup from '@commerce/use-signup' -import type { SignupBody } from '../api/customers/signup' import useCustomer from '../customer/use-customer' +import { SignupMutation, SignupMutationVariables } from '@framework/schema' -const defaultOpts = { - url: '/api/bigcommerce/customers/signup', - method: 'POST', +export const signupMutation = /* GraphQL */ ` + mutation signup($input: RegisterCustomerInput!) { + registerCustomerAccount(input: $input) { + ... on Success { + success + } + } + } +`; + +export type SignupInput = { + email: string; + firstName: string; + lastName: string; + password: string; } -export type SignupInput = SignupBody - -export const fetcher: HookFetcher = ( +export const fetcher: HookFetcher = ( options, - { firstName, lastName, email, password }, + { input }, fetch ) => { - if (!(firstName && lastName && email && password)) { + const { firstName, lastName, emailAddress, password } = input; + if (!(firstName && lastName && emailAddress && password)) { throw new CommerceError({ message: 'A first name, last name, email and password are required to signup', @@ -25,20 +36,27 @@ export const fetcher: HookFetcher = ( } return fetch({ - ...defaultOpts, ...options, - body: { firstName, lastName, email, password }, + query: signupMutation, + variables: { input }, }) } export function extendHook(customFetcher: typeof fetcher) { const useSignup = () => { const { revalidate } = useCustomer() - const fn = useCommerceSignup(defaultOpts, customFetcher) + const fn = useCommerceSignup({}, customFetcher) return useCallback( async function signup(input: SignupInput) { - const data = await fn(input) + const data = await fn({ + input: { + firstName: input.firstName, + lastName: input.lastName, + emailAddress: input.email, + password: input.password, + } + }) await revalidate() return data }, diff --git a/framework/vendure/cart/use-cart.tsx b/framework/vendure/cart/use-cart.tsx index 8372c8d69..ade9b6a91 100644 --- a/framework/vendure/cart/use-cart.tsx +++ b/framework/vendure/cart/use-cart.tsx @@ -34,7 +34,7 @@ export function extendHook( swrOptions?: SwrOptions ) { const useCart = () => { - const response = useData({ query: getCartQuery }, [], customFetcher, swrOptions) + const response = useData({ query: getCartQuery }, [], customFetcher, swrOptions) const res = useResponse(response, { normalizer: (data => { const order = data?.activeOrder || data?.addItemToOrder || data?.adjustOrderLine || data?.removeOrderLine; diff --git a/framework/vendure/customer/use-customer.tsx b/framework/vendure/customer/use-customer.tsx index e5643392d..847229061 100644 --- a/framework/vendure/customer/use-customer.tsx +++ b/framework/vendure/customer/use-customer.tsx @@ -1,33 +1,46 @@ import type { HookFetcher } from '@commerce/utils/types' import type { SwrOptions } from '@commerce/utils/use-data' import useCommerceCustomer from '@commerce/use-customer' -import type { Customer, CustomerData } from '../api/customers' +import { ActiveCustomerQuery } from '@framework/schema' +import useResponse from '@commerce/utils/use-response' -const defaultOpts = { - url: '/api/bigcommerce/customers', - method: 'GET', -} +export const activeCustomerQuery = /* GraphQL */ ` + query activeCustomer { + activeCustomer { + id + firstName + lastName + emailAddress + } + } +`; -export type { Customer } - -export const fetcher: HookFetcher = async ( +export const fetcher: HookFetcher = async ( options, _, fetch ) => { - // const data = await fetch({ ...defaultOpts, ...options }) - // return data?.customer ?? null - return null; + return await fetch({ query: activeCustomerQuery }) } export function extendHook( customFetcher: typeof fetcher, - swrOptions?: SwrOptions + swrOptions?: SwrOptions ) { const useCustomer = () => { - return useCommerceCustomer(defaultOpts, [], customFetcher, { + const response = useCommerceCustomer({}, [], customFetcher, { revalidateOnFocus: false, ...swrOptions, + }); + + return useResponse(response, { + normalizer: data => { + return data?.activeCustomer ? ({ + firstName: data?.activeCustomer?.firstName ?? '', + lastName: data?.activeCustomer?.lastName ?? '', + email: data?.activeCustomer?.emailAddress ?? '', + }) : null; + }, }) } diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 756f7d824..6dd1bdb1c 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -2836,16 +2836,46 @@ export type SearchResultFragment = { __typename?: 'SearchResult' } & Pick< | ({ __typename?: 'SinglePrice' } & Pick) } -export type LoginMutationVariables = Exact<{ +export type LoginServerMutationVariables = Exact<{ email: Scalars['String'] password: Scalars['String'] }> +export type LoginServerMutation = { __typename?: 'Mutation' } & { + login: + | ({ __typename?: 'CurrentUser' } & Pick) + | { __typename?: 'InvalidCredentialsError' } + | { __typename?: 'NotVerifiedError' } + | { __typename?: 'NativeAuthStrategyError' } +} + +export type LoginMutationVariables = Exact<{ + username: Scalars['String'] + password: Scalars['String'] +}> + export type LoginMutation = { __typename?: 'Mutation' } & { login: - | ({ __typename?: 'CurrentUser' } & Pick) - | { __typename?: 'InvalidCredentialsError' } - | { __typename?: 'NotVerifiedError' } + | ({ __typename: 'CurrentUser' } & Pick) + | { __typename: 'InvalidCredentialsError' } + | { __typename: 'NotVerifiedError' } + | { __typename: 'NativeAuthStrategyError' } +} + +export type LogoutMutationVariables = Exact<{ [key: string]: never }> + +export type LogoutMutation = { __typename?: 'Mutation' } & { + logout: { __typename?: 'Success' } & Pick +} + +export type SignupMutationVariables = Exact<{ + input: RegisterCustomerInput +}> + +export type SignupMutation = { __typename?: 'Mutation' } & { + registerCustomerAccount: + | ({ __typename?: 'Success' } & Pick) + | { __typename?: 'MissingPasswordError' } | { __typename?: 'NativeAuthStrategyError' } } @@ -2915,6 +2945,17 @@ export type GetCollectionsQuery = { __typename?: 'Query' } & { } } +export type ActiveCustomerQueryVariables = Exact<{ [key: string]: never }> + +export type ActiveCustomerQuery = { __typename?: 'Query' } & { + activeCustomer?: Maybe< + { __typename?: 'Customer' } & Pick< + Customer, + 'id' | 'firstName' | 'lastName' | 'emailAddress' + > + > +} + export type GetAllProductPathsQueryVariables = Exact<{ first?: Maybe }>