diff --git a/packages/commerce-sdk-react/src/auth/index.test.ts b/packages/commerce-sdk-react/src/auth/index.test.ts index c4a84fcb65..884ff4b2ac 100644 --- a/packages/commerce-sdk-react/src/auth/index.test.ts +++ b/packages/commerce-sdk-react/src/auth/index.test.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import Auth, {injectAccessToken} from './' +import Auth from './' import jwt from 'jsonwebtoken' import {helpers} from 'commerce-sdk-isomorphic' @@ -55,11 +55,6 @@ jest.mock('commerce-sdk-isomorphic', () => { } }) -test('injectAccessToken', () => { - expect(injectAccessToken({}, 'test')).toEqual({Authorization: 'Bearer test'}) - expect(injectAccessToken(undefined, 'test')).toEqual({Authorization: 'Bearer test'}) -}) - const config = { clientId: 'clientId', organizationId: 'organizationId', diff --git a/packages/commerce-sdk-react/src/auth/index.ts b/packages/commerce-sdk-react/src/auth/index.ts index 9984f5908a..fa752ee0c8 100644 --- a/packages/commerce-sdk-react/src/auth/index.ts +++ b/packages/commerce-sdk-react/src/auth/index.ts @@ -4,10 +4,11 @@ * SPDX-License-Identifier: BSD-3-Clause * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import {helpers, ShopperLogin, ShopperLoginTypes} from 'commerce-sdk-isomorphic' +import {helpers, ShopperLogin, ShopperCustomers, ShopperLoginTypes, ShopperCustomersTypes} from 'commerce-sdk-isomorphic' import jwtDecode from 'jwt-decode' -import {ApiClientConfigParams} from '../hooks/types' +import {ApiClientConfigParams, Argument} from '../hooks/types' import {BaseStorage, LocalStorage, CookieStorage} from './storage' +import {CustomerType} from '../hooks/useCustomerType' type Helpers = typeof helpers interface AuthConfig extends ApiClientConfigParams { @@ -55,7 +56,7 @@ type AuthDataMap = Record< * and it's not easy to grab this info in user land, so we add it into the Auth object, and expose it via a hook */ type AuthData = ShopperLoginTypes.TokenResponse & { - customer_type: string + customer_type: CustomerType } const onClient = typeof window !== 'undefined' @@ -134,6 +135,7 @@ const DATA_MAP: AuthDataMap = { */ class Auth { private client: ShopperLogin + private shopperCustomersClient: ShopperCustomers private redirectURI: string private pendingToken: Promise | undefined private REFRESH_TOKEN_EXPIRATION_DAYS = 90 @@ -150,6 +152,17 @@ class Auth { throwOnBadResponse: true, fetchOptions: config.fetchOptions }) + this.shopperCustomersClient = new ShopperCustomers({ + proxy: config.proxy, + parameters: { + clientId: config.clientId, + organizationId: config.organizationId, + shortCode: config.shortCode, + siteId: config.siteId + }, + throwOnBadResponse: true, + fetchOptions: config.fetchOptions + }) if (this.get('site_id') && this.get('site_id') !== config.siteId) { // if site is switched, remove all existing auth data in storage @@ -200,7 +213,7 @@ class Auth { refresh_token: this.get('refresh_token_registered') || this.get('refresh_token_guest'), token_type: this.get('token_type'), usid: this.get('usid'), - customer_type: this.get('customer_type') + customer_type: this.get('customer_type') as CustomerType } } @@ -318,6 +331,35 @@ class Auth { ) } + /** + * This is a wrapper method for ShopperCustomer API registerCustomer endpoint. + * + */ + async register( + body: ShopperCustomersTypes.CustomerRegistration + ) { + const { + customer: {email}, + password + } = body + + // email is optional field from isomorphic library + // type CustomerRegistration + // here we had to guard it to avoid ts error + if (!email) { + throw new Error('Customer registration is missing email address.') + } + + const res = await this.shopperCustomersClient.registerCustomer({ + headers: { + authorization: `Bearer ${this.get('access_token')}` + }, + body + }) + await this.loginRegisteredUserB2C({username: email, password}) + return res + } + /** * A wrapper method for commerce-sdk-isomorphic helper: loginRegisteredUserB2C. * @@ -326,14 +368,12 @@ class Auth { const redirectURI = this.redirectURI const usid = this.get('usid') const isGuest = false - return this.queueRequest( - () => - helpers.loginRegisteredUserB2C(this.client, credentials, { - redirectURI, - ...(usid && {usid}) - }), - isGuest - ) + const token = await helpers.loginRegisteredUserB2C(this.client, credentials, { + redirectURI, + ...(usid && {usid}) + }) + this.handleTokenResponse(token, isGuest) + return token } /** @@ -341,39 +381,11 @@ class Auth { * */ async logout() { - const isGuest = true - return this.queueRequest( - () => - // TODO: are we missing a call to /logout? - // Ticket: https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00001EFF4nYAH/view - helpers.loginGuestUser(this.client, { - redirectURI: this.redirectURI - }), - isGuest - ) + // TODO: are we missing a call to /logout? + // Ticket: https://gus.lightning.force.com/lightning/r/ADM_Work__c/a07EE00001EFF4nYAH/view + this.clearStorage() + return this.loginGuestUser() } } export default Auth - -/** - * A ultility function to inject access token into a headers object. - * - * @Internal - */ -export const injectAccessToken = ( - headers: - | { - [key: string]: string - } - | undefined, - accessToken: string -) => { - const _headers = headers - ? { - ...headers, - Authorization: `Bearer ${accessToken}` - } - : {Authorization: `Bearer ${accessToken}`} - return _headers -} diff --git a/packages/commerce-sdk-react/src/hooks/ShopperCustomers/mutation.ts b/packages/commerce-sdk-react/src/hooks/ShopperCustomers/mutation.ts index c73479221e..af2075e196 100644 --- a/packages/commerce-sdk-react/src/hooks/ShopperCustomers/mutation.ts +++ b/packages/commerce-sdk-react/src/hooks/ShopperCustomers/mutation.ts @@ -431,7 +431,6 @@ export const SHOPPER_CUSTOMERS_NOT_IMPLEMENTED = [ 'authorizeCustomer', 'authorizeTrustedSystem', 'deleteCustomerProductList', - 'getResetPasswordToken', 'invalidateCustomerAuth', 'registerExternalProfile', 'resetPassword', diff --git a/packages/commerce-sdk-react/src/hooks/ShopperLogin/helper.ts b/packages/commerce-sdk-react/src/hooks/ShopperLogin/helper.ts index 4997e75c26..2f5527e7fc 100644 --- a/packages/commerce-sdk-react/src/hooks/ShopperLogin/helper.ts +++ b/packages/commerce-sdk-react/src/hooks/ShopperLogin/helper.ts @@ -14,6 +14,7 @@ import {UseMutationResult} from '@tanstack/react-query' export const ShopperLoginHelpers = { LoginGuestUser: 'loginGuestUser', LoginRegisteredUserB2C: 'loginRegisteredUserB2C', + Register: 'register', Logout: 'logout' } as const @@ -27,14 +28,16 @@ type ShopperLoginHelpersType = typeof ShopperLoginHelpers[keyof typeof ShopperLo * Avaliable helpers: * - loginRegisteredUserB2C * - loginGuestUser + * - register * - logout */ export function useShopperLoginHelper( action: Action ): UseMutationResult< - ShopperLoginTypes.TokenResponse, + // TODO: what's the better way for declaring the types? + any, Error, - void | Argument + any > { const auth = useAuth() if (action === ShopperLoginHelpers.LoginGuestUser) { @@ -43,13 +46,11 @@ export function useShopperLoginHelper( if (action === ShopperLoginHelpers.Logout) { return useMutation(() => auth.logout()) } + if (action === ShopperLoginHelpers.Register) { + return useMutation((body) => auth.register(body)) + } if (action === ShopperLoginHelpers.LoginRegisteredUserB2C) { - return useMutation((credentials) => { - if (!credentials) { - throw new Error('Missing registered user credentials.') - } - return auth.loginRegisteredUserB2C(credentials) - }) + return useMutation((credentials) => auth.loginRegisteredUserB2C(credentials)) } throw new Error('Unknown ShopperLogin helper.') diff --git a/packages/commerce-sdk-react/src/hooks/useCustomerType.ts b/packages/commerce-sdk-react/src/hooks/useCustomerType.ts index 7b22a0115c..3f9de24acf 100644 --- a/packages/commerce-sdk-react/src/hooks/useCustomerType.ts +++ b/packages/commerce-sdk-react/src/hooks/useCustomerType.ts @@ -8,17 +8,47 @@ import useAuth from './useAuth' import useLocalStorage from './useLocalStorage' const onClient = typeof window !== 'undefined' +export type CustomerType = null | 'guest' | 'registered' +type useCustomerType = { + customerType: CustomerType + isGuest: boolean + isRegistered: boolean +} /** - * A hook to return customer auth type, either guest or registered user + * A hook to return customer auth type. + * + * Customer type can have 3 values: + * - null + * - guest + * - registered + * + * During initialization, type is null. And it is possible that + * isGuest and isRegistered to both be false. * */ -const useCustomerType = (): string | null => { +const useCustomerType = (): useCustomerType => { + let customerType = null if (onClient) { - return useLocalStorage('customer_type') + customerType = useLocalStorage('customer_type') + } else { + const auth = useAuth() + customerType = auth.get('customer_type') + } + + const isGuest = customerType === 'guest' + const isRegistered = customerType === 'registered' + + if (customerType !== null && customerType !== 'guest' && customerType !== 'registered') { + console.warn(`Unrecognized customer type found in storage: ${customerType}`) + customerType = null + } + + return { + customerType, + isGuest, + isRegistered } - const auth = useAuth() - return auth.get('customer_type') } export default useCustomerType diff --git a/packages/template-retail-react-app/app/commerce-api/auth.js b/packages/template-retail-react-app/app/commerce-api/auth.js index 7a5dedb7b9..f60523b3fa 100644 --- a/packages/template-retail-react-app/app/commerce-api/auth.js +++ b/packages/template-retail-react-app/app/commerce-api/auth.js @@ -195,6 +195,7 @@ class Auth { * @returns {Promise} */ async login(credentials) { + console.warn('@TODO: old login method is still being used.') // Calling login while its already pending will return a reference // to the existing promise. if (this._pendingLogin) { diff --git a/packages/template-retail-react-app/app/components/_app/index.jsx b/packages/template-retail-react-app/app/components/_app/index.jsx index 4397bbee41..74f1ee386c 100644 --- a/packages/template-retail-react-app/app/components/_app/index.jsx +++ b/packages/template-retail-react-app/app/components/_app/index.jsx @@ -10,6 +10,7 @@ import PropTypes from 'prop-types' import {useHistory, useLocation} from 'react-router-dom' import {getAssetUrl} from 'pwa-kit-react-sdk/ssr/universal/utils' import {getAppOrigin} from 'pwa-kit-react-sdk/utils/url' +import {useCustomerType} from 'commerce-sdk-react-preview' // Chakra import {Box, useDisclosure, useStyleConfig} from '@chakra-ui/react' @@ -82,6 +83,7 @@ Learn more with our localization guide. https://sfdc.co/localization-guide const location = useLocation() const authModal = useAuthModal() const customer = useCustomer() + const {isRegistered} = useCustomerType() const {site, locale, buildUrl} = useMultiSite() const [isOnline, setIsOnline] = useState(true) @@ -145,7 +147,7 @@ Learn more with our localization guide. https://sfdc.co/localization-guide const onAccountClick = () => { // Link to account page for registered customer, open auth modal otherwise - if (customer.isRegistered) { + if (isRegistered) { const path = buildUrl('/account') history.push(path) } else { diff --git a/packages/template-retail-react-app/app/components/drawer-menu/index.jsx b/packages/template-retail-react-app/app/components/drawer-menu/index.jsx index 4e272ba73c..9cb705e34c 100644 --- a/packages/template-retail-react-app/app/components/drawer-menu/index.jsx +++ b/packages/template-retail-react-app/app/components/drawer-menu/index.jsx @@ -41,6 +41,11 @@ import { useBreakpointValue, useMultiStyleConfig } from '@chakra-ui/react' +import { + ShopperLoginHelpers, + useShopperLoginHelper, + useCustomerType +} from 'commerce-sdk-react-preview' import Link from '../../components/link' // Icons import {BrandLogo, LocationIcon, SignoutIcon, UserIcon} from '../icons' @@ -48,7 +53,6 @@ import {BrandLogo, LocationIcon, SignoutIcon, UserIcon} from '../icons' // Others import {noop} from '../../utils/utils' import {getPathWithLocale, categoryUrlBuilder} from '../../utils/url' -import useCustomer from '../../commerce-api/hooks/useCustomer' import LoadingSpinner from '../loading-spinner' import useNavigation from '../../hooks/use-navigation' @@ -79,7 +83,7 @@ const STORE_LOCATOR_HREF = '/store-locator' */ const DrawerMenu = ({isOpen, onClose = noop, onLogoClick = noop, root}) => { const intl = useIntl() - const customer = useCustomer() + const {isRegistered} = useCustomerType() const navigate = useNavigation() const styles = useMultiStyleConfig('DrawerMenu') const drawerSize = useBreakpointValue({sm: PHONE_DRAWER_SIZE, md: TABLET_DRAWER_SIZE}) @@ -87,9 +91,10 @@ const DrawerMenu = ({isOpen, onClose = noop, onLogoClick = noop, root}) => { const {site, buildUrl} = useMultiSite() const {l10n} = site const [showLoading, setShowLoading] = useState(false) + const logout = useShopperLoginHelper(ShopperLoginHelpers.Logout) const onSignoutClick = async () => { setShowLoading(true) - await customer.logout() + await logout.mutateAsync() navigate('/login') setShowLoading(false) } @@ -163,7 +168,7 @@ const DrawerMenu = ({isOpen, onClose = noop, onLogoClick = noop, root}) => { {/* Application Actions */} - {customer.isRegistered ? ( + {isRegistered ? ( `/${locale}/account${item.path}` diff --git a/packages/template-retail-react-app/app/components/header/index.jsx b/packages/template-retail-react-app/app/components/header/index.jsx index f79ee21c72..1e88636024 100644 --- a/packages/template-retail-react-app/app/components/header/index.jsx +++ b/packages/template-retail-react-app/app/components/header/index.jsx @@ -27,9 +27,13 @@ import { useDisclosure, useMediaQuery } from '@chakra-ui/react' +import { + ShopperLoginHelpers, + useShopperLoginHelper, + useCustomerType +} from 'commerce-sdk-react-preview' import {useCurrentBasket} from '../../hooks/use-current-basket' -import useCustomer from '../../commerce-api/hooks/useCustomer' import Link from '../link' import Search from '../search' @@ -80,7 +84,8 @@ const Header = ({ }) => { const intl = useIntl() const {totalItems, basket} = useCurrentBasket() - const customer = useCustomer() + const {isRegistered} = useCustomerType() + const logout = useShopperLoginHelper(ShopperLoginHelpers.Logout) const navigate = useNavigation() const {isOpen, onClose, onOpen} = useDisclosure() @@ -95,7 +100,7 @@ const Header = ({ const onSignoutClick = async () => { setShowLoading(true) - await customer.logout() + await logout.mutateAsync() navigate('/login') setShowLoading(false) } @@ -162,7 +167,7 @@ const Header = ({ })} /> - {customer?.authType === 'registered' && ( + {isRegistered && ( { const {formatMessage} = useIntl() - const customer = useCustomer() + const customerId = useCustomerId() + const {isRegistered} = useCustomerType() + const customer = useCustomer( + {customerId}, + {enabled: !!customerId && isRegistered} + ) const navigate = useNavigation() const [currentView, setCurrentView] = useState(initialView) const form = useForm() const submittedEmail = useRef() const toast = useToast() + const login = useShopperLoginHelper(ShopperLoginHelpers.LoginRegisteredUserB2C) + const register = useShopperLoginHelper(ShopperLoginHelpers.Register) + + // TODO: simplify the args to remove action + const getResetPasswordToken = useShopperCustomersMutation({action: ShopperCustomersMutations.GetResetPasswordToken}) const submitForm = async (data) => { form.clearErrors() - return { - login: handleLogin, - register: handleRegister, - password: handleResetPassword - }[currentView](data) - } - - const handleLogin = async (data) => { - try { - await customer.login(data) - } catch (error) { - const message = /invalid credentials/i.test(error.message) - ? formatMessage({ - defaultMessage: - "Something's not right with your email or password. Try again.", - id: 'auth_modal.error.incorrect_email_or_password' - }) - : formatMessage(API_ERROR_MESSAGE) - form.setError('global', {type: 'manual', message}) - } - } - - const handleRegister = async (data) => { - try { - await customer.registerCustomer(data) + const onLoginSuccess = () => { navigate('/account') - } catch (error) { - form.setError('global', {type: 'manual', message: error.message}) } - } - const handleResetPassword = async ({email}) => { - try { - await customer.getResetPasswordToken(email) - // Execute action to be perfromed on successful passoword reset - await onPasswordResetSuccess() - submittedEmail.current = email - } catch (error) { - form.setError('global', {type: 'manual', message: error.message}) - } + return { + login: (data) => + login.mutateAsync( + {username: data.email, password: data.password}, + { + onSuccess: onLoginSuccess, + onError: (error) => { + const message = /Unauthorized/i.test(error.message) + ? formatMessage({ + defaultMessage: + "Something's not right with your email or password. Try again.", + id: 'auth_modal.error.incorrect_email_or_password' + }) + : formatMessage(API_ERROR_MESSAGE) + form.setError('global', {type: 'manual', message}) + } + } + ), + register: (data) => { + const body = { + customer: { + firstName: data.firstName, + lastName: data.lastName, + email: data.email, + login: data.email + }, + password: data.password + } + + return register.mutateAsync(body, { + onSuccess: onLoginSuccess, + onError: () => { + form.setError('global', { + type: 'manual', + message: formatMessage(API_ERROR_MESSAGE) + }) + } + }) + }, + password: (data) => { + const body = { + login: data.email + } + return getResetPasswordToken.mutateAsync({body}, { + onError: () => { + form.setError('global', { + type: 'manual', + message: formatMessage(API_ERROR_MESSAGE) + }) + } + }) + } + }[currentView](data) } // Reset form and local state when opening the modal useEffect(() => { - if (props.isOpen) { + if (isOpen) { setCurrentView(initialView) submittedEmail.current = undefined form.reset() } - }, [props.isOpen]) + }, [isOpen]) // Auto-focus the first field in each form view useEffect(() => { @@ -122,16 +160,14 @@ export const AuthModal = ({ // Lets determine if the user has either logged in, or registed. const loggingIn = currentView === LOGIN_VIEW const registering = currentView === REGISTER_VIEW - const {isOpen} = props - const isNowRegistered = isOpen && customer.isRegistered && (loggingIn || registering) - + const isNowRegistered = isOpen && isRegistered && (loggingIn || registering) // If the customer changed, but it's not because they logged in or registered. Do nothing. if (!isNowRegistered) { return } // We are done with the modal. - props.onClose() + onClose() // Show a toast only for those registed users returning to the site. if (loggingIn) { @@ -143,7 +179,7 @@ export const AuthModal = ({ id: 'auth_modal.info.welcome_user' }, { - name: customer?.firstName + name: customer.data?.firstName || '' } )}`, description: `${formatMessage({ @@ -163,10 +199,10 @@ export const AuthModal = ({ // Execute action to be performed on successful registration onRegistrationSuccess() } - }, [customer]) + }, [isRegistered]) const onBackToSignInClick = () => - initialView === PASSWORD_VIEW ? props.onClose() : setCurrentView(LOGIN_VIEW) + initialView === PASSWORD_VIEW ? onClose() : setCurrentView(LOGIN_VIEW) const PasswordResetSuccess = () => ( @@ -201,7 +237,15 @@ export const AuthModal = ({ ) return ( - + diff --git a/packages/template-retail-react-app/app/pages/account/index.jsx b/packages/template-retail-react-app/app/pages/account/index.jsx index 51822789d4..2ebafb1a3b 100644 --- a/packages/template-retail-react-app/app/pages/account/index.jsx +++ b/packages/template-retail-react-app/app/pages/account/index.jsx @@ -93,13 +93,14 @@ const Account = () => { ) + // TODO: hook integration WIP // If we have customer data and they are not registered, push to login page // Using Redirect allows us to store the directed page to location // so we can direct users back after they are successfully log in - if (customer.authType != null && !customer.isRegistered) { - const path = buildUrl('/login') - return - } + // if (customer.authType != null && !customer.isRegistered) { + // const path = buildUrl('/login') + // return + // } return ( { const {formatMessage} = useIntl() - const navigate = useNavigation() - const customer = useCustomer() const form = useForm() const location = useLocation() const einstein = useEinstein() + const {isRegistered} = useCustomerType() + const login = useShopperLoginHelper(ShopperLoginHelpers.LoginRegisteredUserB2C) const submitForm = async (data) => { - try { - await customer.login(data) - } catch (error) { - const message = /invalid credentials/i.test(error.message) - ? formatMessage({ - defaultMessage: 'Incorrect username or password, please try again.', - id: 'login_page.error.incorrect_username_or_password' - }) - : error.message - form.setError('global', {type: 'manual', message}) - } + return login.mutateAsync( + {username: data.email, password: data.password}, + { + onError: (error) => { + const message = /Unauthorized/i.test(error.message) + ? formatMessage({ + defaultMessage: + "Incorrect username or password, please try again.", + id: 'login_page.error.incorrect_username_or_password' + }) + : formatMessage(API_ERROR_MESSAGE) + form.setError('global', {type: 'manual', message}) + } + } + ) } // If customer is registered push to account page useEffect(() => { - if (customer.authType != null && customer.isRegistered) { + if (isRegistered) { if (location?.state?.directedFrom) { navigate(location.state.directedFrom) } else { navigate('/account') } } - }, [customer]) + }, [isRegistered]) /**************** Einstein ****************/ useEffect(() => { diff --git a/packages/template-retail-react-app/app/pages/registration/index.jsx b/packages/template-retail-react-app/app/pages/registration/index.jsx index c31a7c3634..752426e606 100644 --- a/packages/template-retail-react-app/app/pages/registration/index.jsx +++ b/packages/template-retail-react-app/app/pages/registration/index.jsx @@ -7,36 +7,53 @@ import React, {useEffect} from 'react' import PropTypes from 'prop-types' +import {useIntl} from 'react-intl' import {Box, Container} from '@chakra-ui/react' -import useCustomer from '../../commerce-api/hooks/useCustomer' -import Seo from '../../components/seo' +import { + ShopperLoginHelpers, + useShopperLoginHelper, + useCustomerType +} from 'commerce-sdk-react-preview' import {useForm} from 'react-hook-form' +import {useLocation} from 'react-router-dom' +import Seo from '../../components/seo' import RegisterForm from '../../components/register' import useNavigation from '../../hooks/use-navigation' import useEinstein from '../../commerce-api/hooks/useEinstein' -import {useLocation} from 'react-router-dom' +import {API_ERROR_MESSAGE} from '../../constants' const Registration = () => { + const {formatMessage} = useIntl() const navigate = useNavigation() - const customer = useCustomer() + const {isRegistered} = useCustomerType() const form = useForm() const einstein = useEinstein() const {pathname} = useLocation() + const register = useShopperLoginHelper(ShopperLoginHelpers.Register) - const submitForm = async (data) => { - try { - await customer.registerCustomer(data) - } catch (error) { - form.setError('global', {type: 'manual', message: error.message}) + const submitForm = (data) => { + const body = { + customer: { + firstName: data.firstName, + lastName: data.lastName, + email: data.email, + login: data.email + }, + password: data.password } + + return register.mutateAsync(body, { + onError: () => { + form.setError('global', {type: 'manual', message: formatMessage(API_ERROR_MESSAGE)}) + } + }) } - // If customer is registered push to account page useEffect(() => { - if (customer.authType != null && customer.isRegistered) { + if (isRegistered) { navigate('/account') } - }, [customer]) + }, [isRegistered]) /**************** Einstein ****************/ useEffect(() => { diff --git a/packages/template-retail-react-app/app/pages/reset-password/index.jsx b/packages/template-retail-react-app/app/pages/reset-password/index.jsx index 55bc6f14d9..a51d42a5fe 100644 --- a/packages/template-retail-react-app/app/pages/reset-password/index.jsx +++ b/packages/template-retail-react-app/app/pages/reset-password/index.jsx @@ -9,9 +9,12 @@ import React, {useState, useEffect} from 'react' import PropTypes from 'prop-types' import {FormattedMessage} from 'react-intl' import {Box, Button, Container, Stack, Text} from '@chakra-ui/react' -import useCustomer from '../../commerce-api/hooks/useCustomer' -import Seo from '../../components/seo' import {useForm} from 'react-hook-form' +import { + useShopperCustomersMutation, + ShopperCustomersMutations +} from 'commerce-sdk-react-preview' +import Seo from '../../components/seo' import ResetPasswordForm from '../../components/reset-password' import {BrandLogo} from '../../components/icons' import useNavigation from '../../hooks/use-navigation' @@ -19,17 +22,21 @@ import useEinstein from '../../commerce-api/hooks/useEinstein' import {useLocation} from 'react-router-dom' const ResetPassword = () => { - const customer = useCustomer() const form = useForm() const navigate = useNavigation() const [submittedEmail, setSubmittedEmail] = useState('') const [showSubmittedSuccess, setShowSubmittedSuccess] = useState(false) const einstein = useEinstein() const {pathname} = useLocation() + // TODO: simplify the args to remove action + const getResetPasswordToken = useShopperCustomersMutation({action: ShopperCustomersMutations.GetResetPasswordToken}) const submitForm = async ({email}) => { + const body = { + login: email + } try { - await customer.getResetPasswordToken(email) + await getResetPasswordToken.mutateAsync({body}) setSubmittedEmail(email) setShowSubmittedSuccess(!showSubmittedSuccess) } catch (error) {