diff --git a/packages/peregrine/lib/store/actions/user/actions.js b/packages/peregrine/lib/store/actions/user/actions.js
index 732545bd51..6fba16f2ad 100755
--- a/packages/peregrine/lib/store/actions/user/actions.js
+++ b/packages/peregrine/lib/store/actions/user/actions.js
@@ -1,7 +1,12 @@
import { createActions } from 'redux-actions';
const prefix = 'USER';
-const actionTypes = ['RESET', 'SET_TOKEN', 'CLEAR_TOKEN'];
+const actionTypes = [
+ 'RESET',
+ 'SET_TOKEN',
+ 'CLEAR_TOKEN',
+ 'SET_USER_ON_ORDER_SUCCESS'
+];
const actionMap = {
SIGN_IN: {
diff --git a/packages/peregrine/lib/store/actions/user/asyncActions.js b/packages/peregrine/lib/store/actions/user/asyncActions.js
index 353187d66c..1ad1f0832b 100755
--- a/packages/peregrine/lib/store/actions/user/asyncActions.js
+++ b/packages/peregrine/lib/store/actions/user/asyncActions.js
@@ -89,3 +89,9 @@ export const clearToken = () =>
// Remove from store
dispatch(actions.clearToken());
};
+
+export const setUserOnOrderSuccess = successFlag =>
+ async function thunk(dispatch) {
+ // Dispatch the action to update the state
+ dispatch(actions.setUserOnOrderSuccess(successFlag));
+ };
diff --git a/packages/peregrine/lib/store/reducers/user.js b/packages/peregrine/lib/store/reducers/user.js
index 73f49ec154..5eede2d035 100755
--- a/packages/peregrine/lib/store/reducers/user.js
+++ b/packages/peregrine/lib/store/reducers/user.js
@@ -30,7 +30,8 @@ const initialState = {
isResettingPassword: false,
isSignedIn: isSignedIn(),
resetPasswordError: null,
- token: getToken()
+ token: getToken(),
+ userOnOrderSuccess: false // Add userOnOrderSuccess state
};
const reducerMap = {
@@ -48,6 +49,12 @@ const reducerMap = {
token: null
};
},
+ [actions.setUserOnOrderSuccess]: (state, { payload }) => {
+ return {
+ ...state,
+ userOnOrderSuccess: payload // Update the state with the new flag value
+ };
+ },
[actions.getDetails.request]: state => {
return {
...state,
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js
index de70d4354a..0bad6eb1b2 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js
@@ -11,6 +11,10 @@ import { useLazyQuery } from '@apollo/client';
import { useUserContext } from '../../../../context/user';
+import { useDispatch } from 'react-redux'; // Import `connect` and `useDispatch` here
+
+import { setUserOnOrderSuccess } from '../../../../store/actions/user/asyncActions'; // Import `setUserOnOrderSuccess`
+
jest.mock('../../../../context/user');
useUserContext.mockImplementation(() => {
return [
@@ -28,6 +32,21 @@ jest.mock('@apollo/client', () => {
};
});
+// Mock `react-redux`'s `useDispatch` and `connect` functions
+
+jest.mock('react-redux', () => ({
+ useDispatch: jest.fn(),
+ connect: jest.fn().mockReturnValue(Component => Component) // Mock `connect` as an identity function
+}));
+
+jest.mock('../../../../store/actions/user/asyncActions', () => ({
+ setUserOnOrderSuccess: jest.fn(value => ({
+ type: 'SET_USER_ON_ORDER_SUCCESS',
+
+ payload: value
+ })) // Mock `setUserOnOrderSuccess` to return an action object
+}));
+
const Component = props => {
const talonProps = useOrderConfirmationPage(props);
@@ -131,6 +150,11 @@ describe('for guest', () => {
}
];
});
+
+ const mockDispatch = jest.fn(); // Mock dispatch for this test
+
+ useDispatch.mockReturnValue(mockDispatch);
+
const tree = createTestInstance();
const { root } = tree;
@@ -143,6 +167,7 @@ describe('for guest', () => {
describe('for authenticated customers', () => {
it('returns the correct shape', () => {
const mockFetch = jest.fn();
+ const mockDispatch = jest.fn(); // Mock dispatch for this test
useLazyQuery.mockReturnValueOnce([
mockFetch,
@@ -153,8 +178,16 @@ describe('for authenticated customers', () => {
}
]);
+ useDispatch.mockReturnValue(mockDispatch);
+
const mockOrderNumber = '12345';
+ // Create a mock dispatch function
+
+ //const mockDispatch = jest.fn();
+
+ //useDispatch.mockReturnValue(mockDispatch); // Mock useDispatch to return the mock function
+
const tree = createTestInstance(
);
@@ -164,6 +197,10 @@ describe('for authenticated customers', () => {
expect(talonProps).toMatchSnapshot();
+ // Check if dispatch was called with the correct action
+
+ expect(mockDispatch).toHaveBeenCalledWith(setUserOnOrderSuccess(true));
+
expect(mockFetch).toHaveBeenCalledWith({
variables: { orderNumber: mockOrderNumber }
});
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useCreateAccount.js b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useCreateAccount.js
index b9176afb3f..b9e378ccb4 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useCreateAccount.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useCreateAccount.js
@@ -9,6 +9,7 @@ import { useGoogleReCaptcha } from '../../../hooks/useGoogleReCaptcha';
import DEFAULT_OPERATIONS from './createAccount.gql';
import { useEventingContext } from '../../../context/eventing';
+import { useHistory } from 'react-router-dom';
/**
* Returns props necessary to render CreateAccount component. In particular this
@@ -95,6 +96,7 @@ export const useCreateAccount = props => {
formAction: 'createAccount'
});
+ const history = useHistory();
const handleSubmit = useCallback(
async formValues => {
setIsSubmitting(true);
@@ -158,6 +160,8 @@ export const useCreateAccount = props => {
if (onSubmit) {
onSubmit();
}
+
+ history.push('/account-information');
} catch (error) {
if (process.env.NODE_ENV !== 'production') {
console.error(error);
@@ -179,7 +183,8 @@ export const useCreateAccount = props => {
removeCart,
setToken,
signIn,
- dispatch
+ dispatch,
+ history
]
);
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
index 2c7f75e185..4a7259fb10 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
@@ -1,9 +1,11 @@
import { useEffect } from 'react';
import { useUserContext } from '../../../context/user';
+import { setUserOnOrderSuccess } from '../../../store/actions/user/asyncActions';
import { useLazyQuery } from '@apollo/client';
import mergeOperations from '../../../util/shallowMerge';
import DEFAULT_OPERATIONS from './orderConfirmationPage.gql';
+import { useDispatch } from 'react-redux';
export const flattenGuestCartData = data => {
if (!data) {
@@ -34,8 +36,13 @@ export const flattenCustomerOrderData = data => {
if (!data) {
return;
}
+
const { customer } = data;
- const order = customer.orders.items[0];
+ const order = customer?.orders?.items?.[0];
+ if (!order || !order.shipping_address) {
+ // Return an empty response if no valid order or shipping address exists
+ return;
+ }
const { shipping_address: address } = order;
return {
@@ -65,6 +72,8 @@ export const useOrderConfirmationPage = props => {
const flatData =
flattenGuestCartData(props.data) || flattenCustomerOrderData(queryData);
+ const dispatch = useDispatch();
+
useEffect(() => {
if (props.orderNumber && !props.data) {
const orderNumber = props.orderNumber;
@@ -74,7 +83,19 @@ export const useOrderConfirmationPage = props => {
}
});
}
- }, [props.orderNumber, props.data, fetchOrderConfirmationDetails]);
+
+ dispatch(setUserOnOrderSuccess(true));
+
+ return () => {
+ // Reset the flag when leaving the page
+ dispatch(setUserOnOrderSuccess(false));
+ };
+ }, [
+ props.orderNumber,
+ props.data,
+ fetchOrderConfirmationDetails,
+ dispatch
+ ]);
return {
flatData,
diff --git a/packages/peregrine/lib/talons/CreateAccount/__tests__/useCreateAccount.spec.js b/packages/peregrine/lib/talons/CreateAccount/__tests__/useCreateAccount.spec.js
index 6c22e62abe..457d71c06b 100644
--- a/packages/peregrine/lib/talons/CreateAccount/__tests__/useCreateAccount.spec.js
+++ b/packages/peregrine/lib/talons/CreateAccount/__tests__/useCreateAccount.spec.js
@@ -9,6 +9,17 @@ import { retrieveCartId } from '../../../store/actions/cart';
import createTestInstance from '../../../util/createTestInstance';
import { useCreateAccount } from '../useCreateAccount';
import { useEventingContext } from '../../../context/eventing';
+import { useHistory, useLocation } from 'react-router-dom'; // Added import for useHistory and useLocation
+
+// Mocking useHistory and useLocation
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'), // Keep the other functionality intact
+
+ useHistory: jest.fn(),
+
+ useLocation: jest.fn()
+}));
jest.mock('@apollo/client', () => {
const apolloClient = jest.requireActual('@apollo/client');
@@ -186,6 +197,22 @@ beforeAll(() => {
});
useApolloClient.mockReturnValue(client);
+
+ // Mock useHistory and useLocation here if needed for specific tests
+
+ useHistory.mockReturnValue({
+ push: jest.fn() // You can mock any methods that useHistory would provide
+ });
+
+ useLocation.mockReturnValue({
+ pathname: '/mock-path',
+
+ search: '',
+
+ hash: '',
+
+ state: null
+ });
});
test('should return properly', () => {
diff --git a/packages/peregrine/lib/talons/CreateAccount/useCreateAccount.js b/packages/peregrine/lib/talons/CreateAccount/useCreateAccount.js
index 68922ca694..93d43b30cb 100644
--- a/packages/peregrine/lib/talons/CreateAccount/useCreateAccount.js
+++ b/packages/peregrine/lib/talons/CreateAccount/useCreateAccount.js
@@ -10,6 +10,12 @@ import { useGoogleReCaptcha } from '../../hooks/useGoogleReCaptcha';
import DEFAULT_OPERATIONS from './createAccount.gql';
import { useEventingContext } from '../../context/eventing';
+import { useHistory, useLocation } from 'react-router-dom';
+
+/**
+ * Routes to redirect from if used to create an account.
+ */
+const REDIRECT_FOR_ROUTES = ['/checkout', '/order-confirmation'];
/**
* Returns props necessary to render CreateAccount component. In particular this
@@ -47,7 +53,7 @@ export const useCreateAccount = props => {
{ createCart, removeCart, getCartDetails }
] = useCartContext();
const [
- { isGettingDetails },
+ { isGettingDetails, userOnOrderSuccess },
{ getUserDetails, setToken }
] = useUserContext();
@@ -112,6 +118,9 @@ export const useCreateAccount = props => {
};
}, [handleCancel]);
+ const history = useHistory();
+ const location = useLocation();
+
const handleSubmit = useCallback(
async formValues => {
setIsSubmitting(true);
@@ -188,6 +197,13 @@ export const useCreateAccount = props => {
if (onSubmit) {
onSubmit();
}
+
+ if (
+ userOnOrderSuccess &&
+ REDIRECT_FOR_ROUTES.includes(location.pathname)
+ ) {
+ history.push('/account-information');
+ }
} catch (error) {
if (process.env.NODE_ENV !== 'production') {
console.error(error);
@@ -213,7 +229,10 @@ export const useCreateAccount = props => {
getCartDetails,
fetchCartDetails,
onSubmit,
- dispatch
+ dispatch,
+ history,
+ location.pathname,
+ userOnOrderSuccess
]
);
diff --git a/packages/peregrine/lib/talons/SignIn/__tests__/useSignIn.spec.js b/packages/peregrine/lib/talons/SignIn/__tests__/useSignIn.spec.js
index 42845b790a..db93f04cde 100644
--- a/packages/peregrine/lib/talons/SignIn/__tests__/useSignIn.spec.js
+++ b/packages/peregrine/lib/talons/SignIn/__tests__/useSignIn.spec.js
@@ -53,6 +53,24 @@ jest.mock('@magento/peregrine/lib/context/eventing', () => ({
useEventingContext: jest.fn().mockReturnValue([{}, { dispatch: jest.fn() }])
}));
+jest.mock('react-router-dom', () => ({
+ useHistory: jest.fn().mockReturnValue({
+ push: jest.fn(),
+
+ replace: jest.fn()
+ }),
+
+ useLocation: jest.fn().mockReturnValue({
+ pathname: '/checkout',
+
+ search: '',
+
+ hash: '',
+
+ state: null
+ })
+}));
+
const Component = props => {
const talonProps = useSignIn(props);
@@ -277,6 +295,12 @@ test('mutation error is returned by talon', async () => {
expect(talonProps.errors).toMatchSnapshot();
});
+test('useLocation and useHistory are used correctly', () => {
+ const { talonProps } = getTalonProps({ ...defaultProps });
+
+ expect(talonProps).toBeDefined(); // Placeholder assertion.
+});
+
it('should call handleForgotPassword when Enter key is pressed', () => {
const { talonProps } = getTalonProps({
...defaultProps
diff --git a/packages/peregrine/lib/talons/SignIn/useSignIn.js b/packages/peregrine/lib/talons/SignIn/useSignIn.js
index 34fb99f043..ef0551eb51 100644
--- a/packages/peregrine/lib/talons/SignIn/useSignIn.js
+++ b/packages/peregrine/lib/talons/SignIn/useSignIn.js
@@ -10,6 +10,12 @@ import { retrieveCartId } from '../../store/actions/cart';
import DEFAULT_OPERATIONS from './signIn.gql';
import { useEventingContext } from '../../context/eventing';
+import { useHistory, useLocation } from 'react-router-dom';
+
+/**
+ * Routes to redirect from if used to create an account.
+ */
+const REDIRECT_FOR_ROUTES = ['/checkout', '/order-confirmation'];
export const useSignIn = props => {
const {
@@ -40,7 +46,7 @@ export const useSignIn = props => {
const userContext = useUserContext();
const [
- { isGettingDetails, getDetailsError },
+ { isGettingDetails, getDetailsError, userOnOrderSuccess },
{ getUserDetails, setToken }
] = userContext;
@@ -83,6 +89,9 @@ export const useSignIn = props => {
const formApiRef = useRef(null);
const setFormApi = useCallback(api => (formApiRef.current = api), []);
+ const history = useHistory();
+ const location = useLocation();
+
const handleSubmit = useCallback(
async ({ email, password }) => {
setIsSigningIn(true);
@@ -144,6 +153,13 @@ export const useSignIn = props => {
});
getCartDetails({ fetchCartId, fetchCartDetails });
+
+ if (
+ userOnOrderSuccess &&
+ REDIRECT_FOR_ROUTES.includes(location.pathname)
+ ) {
+ history.push('/order-history');
+ }
} catch (error) {
if (process.env.NODE_ENV !== 'production') {
console.error(error);
@@ -168,7 +184,10 @@ export const useSignIn = props => {
getCartDetails,
fetchCartDetails,
dispatch,
- handleTriggerClick
+ handleTriggerClick,
+ history,
+ location.pathname,
+ userOnOrderSuccess
]
);
diff --git a/packages/venia-ui/lib/components/CreateAccount/__tests__/createAccount.spec.js b/packages/venia-ui/lib/components/CreateAccount/__tests__/createAccount.spec.js
index c174a60ae3..f2cd3e6638 100644
--- a/packages/venia-ui/lib/components/CreateAccount/__tests__/createAccount.spec.js
+++ b/packages/venia-ui/lib/components/CreateAccount/__tests__/createAccount.spec.js
@@ -4,6 +4,8 @@ import { createTestInstance } from '@magento/peregrine';
import CreateAccount from '../createAccount';
+import { useHistory, useLocation } from 'react-router-dom';
+
jest.mock('@apollo/client', () => ({
gql: jest.fn(),
useApolloClient: jest.fn().mockImplementation(() => {}),
@@ -24,6 +26,16 @@ jest.mock('@apollo/client', () => ({
}))
}));
+// Mocking the react-router hooks
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+
+ useHistory: jest.fn(),
+
+ useLocation: jest.fn()
+}));
+
jest.mock('../../../util/formValidators');
jest.mock('@magento/peregrine/lib/context/user', () => {
const userState = {
@@ -58,6 +70,24 @@ jest.mock('@magento/peregrine/lib/hooks/useAwaitQuery', () => {
return { useAwaitQuery };
});
+// Mocking useLocation and useHistory for the tests
+
+beforeEach(() => {
+ useHistory.mockReturnValue({
+ push: jest.fn() // mock any methods you need from useHistory
+ });
+
+ useLocation.mockReturnValue({
+ pathname: '/mock-path', // mock the location properties
+
+ search: '',
+
+ hash: '',
+
+ state: null
+ });
+});
+
jest.mock('@magento/peregrine/lib/context/eventing', () => ({
useEventingContext: jest.fn().mockReturnValue([{}, { dispatch: jest.fn() }])
}));
diff --git a/packages/venia-ui/lib/components/SignIn/__tests__/signIn.spec.js b/packages/venia-ui/lib/components/SignIn/__tests__/signIn.spec.js
index f8249d57c5..feb4eb699f 100755
--- a/packages/venia-ui/lib/components/SignIn/__tests__/signIn.spec.js
+++ b/packages/venia-ui/lib/components/SignIn/__tests__/signIn.spec.js
@@ -8,6 +8,8 @@ import SignIn from '../signIn';
import { useUserContext } from '@magento/peregrine/lib/context/user';
import { useMutation } from '@apollo/client';
+import { useHistory, useLocation } from 'react-router-dom';
+
jest.mock('@apollo/client', () => ({
gql: jest.fn(),
useApolloClient: jest.fn().mockImplementation(() => {}),
@@ -23,6 +25,17 @@ jest.mock('@apollo/client', () => ({
loading: false
}))
}));
+
+// Mocking the react-router hooks
+
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+
+ useHistory: jest.fn(),
+
+ useLocation: jest.fn()
+}));
+
jest.mock('../../../classify');
jest.mock('../../Button', () => () => );
jest.mock('../../FormError/formError', () => 'FormError');
@@ -67,6 +80,24 @@ jest.mock('@magento/peregrine/lib/context/eventing', () => ({
useEventingContext: jest.fn().mockReturnValue([{}, { dispatch: jest.fn() }])
}));
+// Mocking useLocation and useHistory for the tests
+
+beforeEach(() => {
+ useHistory.mockReturnValue({
+ push: jest.fn() // mock any methods you need from useHistory
+ });
+
+ useLocation.mockReturnValue({
+ pathname: '/mock-path', // mock the location properties
+
+ search: '',
+
+ hash: '',
+
+ state: null
+ });
+});
+
const props = {
setDefaultUsername: jest.fn(),
showCreateAccount: jest.fn(),