diff --git a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__fixtures__/cartItems.js b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__fixtures__/cartItems.js
index 93ebf7be41..e2dac48fe3 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__fixtures__/cartItems.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__fixtures__/cartItems.js
@@ -1,102 +1,129 @@
-export default {
- cart: {
- id: 'GXtkt675mPd3gYuvhWLd5iw5ekVoDj1b',
- total_quantity: 7,
- items: [
+export default [
+ {
+ id: '29568',
+ product: {
+ id: 1093,
+ name: 'Jillian Top',
+ thumbnail: {
+ url:
+ 'https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/t/vt12-kh_main_2.jpg',
+ __typename: 'ProductImage'
+ },
+ __typename: 'ConfigurableProduct'
+ },
+ quantity: 3,
+ configurable_options: [
+ {
+ configurable_product_option_uid: 179,
+ option_label: 'Fashion Color',
+ configurable_product_option_value_uid: 18,
+ value_label: 'Peach',
+ __typename: 'SelectedConfigurableOption'
+ },
+ {
+ configurable_product_option_uid: 182,
+ option_label: 'Fashion Size',
+ configurable_product_option_value_uid: 27,
+ value_label: 'M',
+ __typename: 'SelectedConfigurableOption'
+ }
+ ],
+ __typename: 'ConfigurableCartItem'
+ },
+ {
+ id: '29570',
+ product: {
+ id: 1115,
+ name: 'Juno Sweater',
+ thumbnail: {
+ url:
+ 'https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/s/vsw02-pe_main_2.jpg',
+ __typename: 'ProductImage'
+ },
+ __typename: 'ConfigurableProduct'
+ },
+ quantity: 1,
+ configurable_options: [
+ {
+ configurable_product_option_uid: 179,
+ option_label: 'Fashion Color',
+ configurable_product_option_value_uid: 21,
+ value_label: 'Rain',
+ __typename: 'SelectedConfigurableOption'
+ },
{
- id: '29568',
- product: {
- id: 1093,
- name: 'Jillian Top',
- thumbnail: {
- url:
- 'https://master-7rqtwti-c5v7sxvquxwl4.eu-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/t/vt12-kh_main_2.jpg',
- __typename: 'ProductImage'
- },
- __typename: 'ConfigurableProduct'
- },
- quantity: 3,
- configurable_options: [
- {
- configurable_product_option_uid: 179,
- option_label: 'Fashion Color',
- configurable_product_option_value_uid: 18,
- value_label: 'Peach',
- __typename: 'SelectedConfigurableOption'
- },
- {
- configurable_product_option_uid: 182,
- option_label: 'Fashion Size',
- configurable_product_option_value_uid: 27,
- value_label: 'M',
- __typename: 'SelectedConfigurableOption'
- }
- ],
- __typename: 'ConfigurableCartItem'
+ configurable_product_option_uid: 182,
+ option_label: 'Fashion Size',
+ configurable_product_option_value_uid: 29,
+ value_label: 'XS',
+ __typename: 'SelectedConfigurableOption'
+ }
+ ],
+ __typename: 'ConfigurableCartItem'
+ },
+ {
+ id: '29572',
+ product: {
+ id: 1152,
+ name: 'Angelina Tank Dress',
+ thumbnail: {
+ url:
+ 'https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/d/vd01-ll_main_2.jpg',
+ __typename: 'ProductImage'
+ },
+ __typename: 'ConfigurableProduct'
+ },
+ quantity: 3,
+ configurable_options: [
+ {
+ configurable_product_option_uid: 179,
+ option_label: 'Fashion Color',
+ configurable_product_option_value_uid: 20,
+ value_label: 'Lilac',
+ __typename: 'SelectedConfigurableOption'
+ },
+ {
+ configurable_product_option_uid: 182,
+ option_label: 'Fashion Size',
+ configurable_product_option_value_uid: 26,
+ value_label: 'L',
+ __typename: 'SelectedConfigurableOption'
+ }
+ ],
+ __typename: 'ConfigurableCartItem'
+ }
+];
+
+export const singleItem = [
+ {
+ id: '29568',
+ product: {
+ id: 1093,
+ name: 'Jillian Top',
+ thumbnail: {
+ url:
+ 'https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/t/vt12-kh_main_2.jpg',
+ __typename: 'ProductImage'
},
+ __typename: 'ConfigurableProduct'
+ },
+ quantity: 3,
+ configurable_options: [
{
- id: '29570',
- product: {
- id: 1115,
- name: 'Juno Sweater',
- thumbnail: {
- url:
- 'https://master-7rqtwti-c5v7sxvquxwl4.eu-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/s/vsw02-pe_main_2.jpg',
- __typename: 'ProductImage'
- },
- __typename: 'ConfigurableProduct'
- },
- quantity: 1,
- configurable_options: [
- {
- configurable_product_option_uid: 179,
- option_label: 'Fashion Color',
- configurable_product_option_value_uid: 21,
- value_label: 'Rain',
- __typename: 'SelectedConfigurableOption'
- },
- {
- configurable_product_option_uid: 182,
- option_label: 'Fashion Size',
- configurable_product_option_value_uid: 29,
- value_label: 'XS',
- __typename: 'SelectedConfigurableOption'
- }
- ],
- __typename: 'ConfigurableCartItem'
+ configurable_product_option_uid: 179,
+ option_label: 'Fashion Color',
+ configurable_product_option_value_uid: 18,
+ value_label: 'Peach',
+ __typename: 'SelectedConfigurableOption'
},
{
- id: '29572',
- product: {
- id: 1152,
- name: 'Angelina Tank Dress',
- thumbnail: {
- url:
- 'https://master-7rqtwti-c5v7sxvquxwl4.eu-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/d/vd01-ll_main_2.jpg',
- __typename: 'ProductImage'
- },
- __typename: 'ConfigurableProduct'
- },
- quantity: 3,
- configurable_options: [
- {
- configurable_product_option_uid: 179,
- option_label: 'Fashion Color',
- configurable_product_option_value_uid: 20,
- value_label: 'Lilac',
- __typename: 'SelectedConfigurableOption'
- },
- {
- configurable_product_option_uid: 182,
- option_label: 'Fashion Size',
- configurable_product_option_value_uid: 26,
- value_label: 'L',
- __typename: 'SelectedConfigurableOption'
- }
- ],
- __typename: 'ConfigurableCartItem'
+ configurable_product_option_uid: 182,
+ option_label: 'Fashion Size',
+ configurable_product_option_value_uid: 27,
+ value_label: 'M',
+ __typename: 'SelectedConfigurableOption'
}
],
- __typename: 'Cart'
+ __typename: 'ConfigurableCartItem'
}
-};
+];
diff --git a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/__snapshots__/useItemsReview.spec.js.snap b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/__snapshots__/useItemsReview.spec.js.snap
index 6f543c1a49..34821e73ac 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/__snapshots__/useItemsReview.spec.js.snap
+++ b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/__snapshots__/useItemsReview.spec.js.snap
@@ -3,27 +3,100 @@
exports[`returns correct shape 1`] = `
Object {
"configurableThumbnailSource": "parent",
- "hasErrors": false,
- "isLoading": true,
- "items": Array [],
- "setShowAllItems": [Function],
- "showAllItems": false,
- "totalQuantity": 0,
-}
-`;
-
-exports[`uses static data if provided 1`] = `
-Object {
- "configurableThumbnailSource": "parent",
- "hasErrors": false,
- "isLoading": true,
"items": Array [
Object {
- "name": "static item",
+ "__typename": "ConfigurableCartItem",
+ "configurable_options": Array [
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 179,
+ "configurable_product_option_value_uid": 18,
+ "option_label": "Fashion Color",
+ "value_label": "Peach",
+ },
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 182,
+ "configurable_product_option_value_uid": 27,
+ "option_label": "Fashion Size",
+ "value_label": "M",
+ },
+ ],
+ "id": "29568",
+ "product": Object {
+ "__typename": "ConfigurableProduct",
+ "id": 1093,
+ "name": "Jillian Top",
+ "thumbnail": Object {
+ "__typename": "ProductImage",
+ "url": "https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/t/vt12-kh_main_2.jpg",
+ },
+ },
+ "quantity": 3,
+ },
+ Object {
+ "__typename": "ConfigurableCartItem",
+ "configurable_options": Array [
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 179,
+ "configurable_product_option_value_uid": 21,
+ "option_label": "Fashion Color",
+ "value_label": "Rain",
+ },
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 182,
+ "configurable_product_option_value_uid": 29,
+ "option_label": "Fashion Size",
+ "value_label": "XS",
+ },
+ ],
+ "id": "29570",
+ "product": Object {
+ "__typename": "ConfigurableProduct",
+ "id": 1115,
+ "name": "Juno Sweater",
+ "thumbnail": Object {
+ "__typename": "ProductImage",
+ "url": "https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/s/vsw02-pe_main_2.jpg",
+ },
+ },
+ "quantity": 1,
+ },
+ Object {
+ "__typename": "ConfigurableCartItem",
+ "configurable_options": Array [
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 179,
+ "configurable_product_option_value_uid": 20,
+ "option_label": "Fashion Color",
+ "value_label": "Lilac",
+ },
+ Object {
+ "__typename": "SelectedConfigurableOption",
+ "configurable_product_option_uid": 182,
+ "configurable_product_option_value_uid": 26,
+ "option_label": "Fashion Size",
+ "value_label": "L",
+ },
+ ],
+ "id": "29572",
+ "product": Object {
+ "__typename": "ConfigurableProduct",
+ "id": 1152,
+ "name": "Angelina Tank Dress",
+ "thumbnail": Object {
+ "__typename": "ProductImage",
+ "url": "https://master-7rqtwti-c5v7sxvquxwl4.us-4.magentosite.cloud/media/catalog/product/cache/d3ba9f7bcd3b0724e976dc5144b29c7d/v/d/vd01-ll_main_2.jpg",
+ },
+ },
+ "quantity": 3,
},
],
"setShowAllItems": [Function],
- "showAllItems": true,
- "totalQuantity": 1,
+ "showAllItems": false,
+ "totalQuantity": 7,
}
`;
diff --git a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/useItemsReview.spec.js b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/useItemsReview.spec.js
index 4bd9e02804..73b9cdad47 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/useItemsReview.spec.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/__tests__/useItemsReview.spec.js
@@ -1,40 +1,21 @@
import React from 'react';
-import { useLazyQuery, useQuery } from '@apollo/client';
+import { useQuery } from '@apollo/client';
import createTestInstance from '../../../../../lib/util/createTestInstance';
import { useItemsReview } from '../useItemsReview';
-import cartItems from '../__fixtures__/cartItems';
+import cartItems, { singleItem } from '../__fixtures__/cartItems';
jest.mock('@apollo/client', () => {
const apolloClient = jest.requireActual('@apollo/client');
return {
...apolloClient,
- useQuery: jest.fn(),
- useLazyQuery: jest.fn()
+ useQuery: jest.fn()
};
});
-jest.mock('../../../../context/cart', () => {
- const state = {
- cartId: 'cart123'
- };
- const api = {};
- const useCartContext = jest.fn(() => [state, api]);
-
- return { useCartContext };
-});
-
beforeAll(() => {
- useLazyQuery.mockReturnValue([
- () => {},
- {
- data: null,
- error: null,
- loading: true
- }
- ]);
useQuery.mockReturnValue({
data: {
storeConfig: {
@@ -52,98 +33,48 @@ const Component = props => {
};
test('returns correct shape', () => {
- const tree = createTestInstance(
-
- );
+ const tree = createTestInstance();
const { root } = tree;
const { talonProps } = root.findByType('i').props;
expect(talonProps).toMatchSnapshot();
});
-test('uses static data if provided', () => {
- const queries = { getItemsInCart: jest.fn() };
- const data = {
- cart: {
- items: [
- {
- name: 'static item'
- }
- ],
- total_quantity: 1
- }
- };
- const tree = createTestInstance(
-
- );
+test('Should return correct total quantity', () => {
+ const tree = createTestInstance();
const { root } = tree;
const { talonProps } = root.findByType('i').props;
- expect(talonProps).toMatchSnapshot();
-});
+ const expectedQuantity = 7;
-test('Should return total quantity from gql query', () => {
- useLazyQuery.mockReturnValueOnce([
- () => {},
- {
- data: cartItems,
- error: null,
- loading: false
- }
- ]);
- const tree = createTestInstance(
-
- );
- const { root } = tree;
- const { talonProps } = root.findByType('i').props;
-
- expect(talonProps.totalQuantity).toBe(cartItems.cart.total_quantity);
+ expect(talonProps.totalQuantity).toBe(expectedQuantity);
});
-test('Should return 0 for total quantity if gql does not return total_quality', () => {
- const newCartItems = {
- ...cartItems
- };
- newCartItems.cart.total_quantity = null;
- useLazyQuery.mockReturnValueOnce([
- () => {},
- {
- data: newCartItems,
- error: null,
- loading: false
- }
- ]);
- const tree = createTestInstance(
-
- );
+test('Should cases where no item data is provided', () => {
+ const tree = createTestInstance();
const { root } = tree;
const { talonProps } = root.findByType('i').props;
expect(talonProps.totalQuantity).toBe(0);
+ expect(talonProps.items).toEqual([]);
});
-test('hasErrors in return props should be set to true if gql throws any errors', () => {
- useLazyQuery.mockReturnValueOnce([
- () => {},
- { data: null, loading: false, error: 'some error' }
- ]);
+test('handles no configurable thumbnail source data', () => {
+ useQuery.mockReturnValueOnce({});
+
const tree = createTestInstance(
);
const { root } = tree;
const { talonProps } = root.findByType('i').props;
- expect(talonProps.hasErrors).toBeTruthy();
+ expect(talonProps.configurableThumbnailSource).toBeUndefined();
});
-test('handles no configurable thumbnail source data', () => {
- useQuery.mockReturnValueOnce({});
-
- const tree = createTestInstance(
-
- );
+test('set show all items to true when there is less than two items in the cart', () => {
+ const tree = createTestInstance();
const { root } = tree;
const { talonProps } = root.findByType('i').props;
- expect(talonProps.configurableThumbnailSource).toBeUndefined();
+ expect(talonProps.showAllItems).toBeTruthy();
});
diff --git a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/useItemsReview.js b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/useItemsReview.js
index 03298b8a5d..28f1194285 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/useItemsReview.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/ItemsReview/useItemsReview.js
@@ -1,7 +1,6 @@
import { useEffect, useState, useCallback, useMemo } from 'react';
-import { useLazyQuery, useQuery } from '@apollo/client';
+import { useQuery } from '@apollo/client';
-import { useCartContext } from '../../../context/cart';
import mergeOperations from '../../../util/shallowMerge';
import DEFAULT_OPERATIONS from './itemsReview.gql';
@@ -9,9 +8,9 @@ export const useItemsReview = props => {
const [showAllItems, setShowAllItems] = useState(false);
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
- const { getItemsInCart, getConfigurableThumbnailSource } = operations;
+ const { getConfigurableThumbnailSource } = operations;
- const [{ cartId }] = useCartContext();
+ const { items: itemsData } = props;
const { data: configurableThumbnailSourceData } = useQuery(
getConfigurableThumbnailSource,
@@ -27,48 +26,29 @@ export const useItemsReview = props => {
}
}, [configurableThumbnailSourceData]);
- const [
- fetchItemsInCart,
- { data: queryData, error, loading }
- ] = useLazyQuery(getItemsInCart, {
- fetchPolicy: 'cache-and-network'
- });
-
- // If static data was provided, use that instead of query data.
- const data = props.data || queryData;
-
const setShowAllItemsFlag = useCallback(() => setShowAllItems(true), [
setShowAllItems
]);
- useEffect(() => {
- if (cartId && !props.data) {
- fetchItemsInCart({
- variables: {
- cartId
- }
- });
- }
- }, [cartId, fetchItemsInCart, props.data]);
-
useEffect(() => {
/**
* If there are 2 or less than 2 items in cart
* set show all items to `true`.
*/
- if (data && data.cart && data.cart.items.length <= 2) {
+ if (itemsData && itemsData.length <= 2) {
setShowAllItems(true);
}
- }, [data]);
+ }, [itemsData]);
- const items = data ? data.cart.items : [];
+ const items = itemsData || [];
- const totalQuantity = data ? +data.cart.total_quantity : 0;
+ const totalQuantity = items.reduce(
+ (previousValue, currentValue) => previousValue + currentValue.quantity,
+ 0
+ );
return {
- isLoading: !!loading,
items,
- hasErrors: !!error,
totalQuantity,
showAllItems,
setShowAllItems: setShowAllItemsFlag,
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/__snapshots__/useOrderConfirmationPage.spec.js.snap b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/__snapshots__/useOrderConfirmationPage.spec.js.snap
index aa2b8a1207..fc533a8265 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/__snapshots__/useOrderConfirmationPage.spec.js.snap
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/__snapshots__/useOrderConfirmationPage.spec.js.snap
@@ -1,7 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`returns the correct shape 1`] = `
+exports[`for authenticated customers returns the correct shape 1`] = `
Object {
+ "error": undefined,
"flatData": Object {
"city": "city",
"country": "country",
@@ -14,8 +15,29 @@ Object {
"street": Array [
"street",
],
- "totalItemQuantity": 1,
},
"isSignedIn": true,
+ "loading": false,
+}
+`;
+
+exports[`for guest returns the correct shape 1`] = `
+Object {
+ "error": undefined,
+ "flatData": Object {
+ "city": "city",
+ "country": "country",
+ "email": "email",
+ "firstname": "firstname",
+ "lastname": "lastname",
+ "postcode": "postcode",
+ "region": "region",
+ "shippingMethod": "carrier - method",
+ "street": Array [
+ "street",
+ ],
+ },
+ "isSignedIn": false,
+ "loading": undefined,
}
`;
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 8772608a1b..de70d4354a 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/__tests__/useOrderConfirmationPage.spec.js
@@ -1,8 +1,14 @@
import React from 'react';
-import { flatten, useOrderConfirmationPage } from '../useOrderConfirmationPage';
+import {
+ flattenCustomerOrderData,
+ flattenGuestCartData,
+ useOrderConfirmationPage
+} from '../useOrderConfirmationPage';
import createTestInstance from '../../../../../lib/util/createTestInstance';
+import { useLazyQuery } from '@apollo/client';
+
import { useUserContext } from '../../../../context/user';
jest.mock('../../../../context/user');
@@ -14,13 +20,21 @@ useUserContext.mockImplementation(() => {
];
});
+jest.mock('@apollo/client', () => {
+ const apolloClient = jest.requireActual('@apollo/client');
+ return {
+ ...apolloClient,
+ useLazyQuery: jest.fn().mockReturnValue([jest.fn(), {}])
+ };
+});
+
const Component = props => {
const talonProps = useOrderConfirmationPage(props);
return ;
};
-const mockData = {
+const mockGuestCartData = {
cart: {
email: 'email',
shipping_addresses: [
@@ -46,33 +60,112 @@ const mockData = {
total_quantity: 1
}
};
+
+const mockCustomerOrderData = {
+ customer: {
+ email: 'email',
+ orders: {
+ items: [
+ {
+ shipping_address: {
+ firstname: 'firstname',
+ lastname: 'lastname',
+ street: ['street'],
+ city: 'city',
+ region: 'region',
+ postcode: 'postcode',
+ country_code: 'country'
+ },
+ shipping_method: 'carrier - method'
+ }
+ ]
+ }
+ }
+};
+
const DEFAULT_PROPS = {
- data: mockData
+ data: mockGuestCartData
+};
+
+const expectedFlatData = {
+ city: 'city',
+ country: 'country',
+ email: 'email',
+ firstname: 'firstname',
+ lastname: 'lastname',
+ postcode: 'postcode',
+ region: 'region',
+ shippingMethod: 'carrier - method',
+ street: ['street']
};
-describe('#flatten', () => {
+describe('#flattenGuestCartData', () => {
+ it('returns flat cart data', () => {
+ expect(flattenGuestCartData(mockGuestCartData)).toEqual(
+ expectedFlatData
+ );
+ });
+
+ it('returns nothing when there is no data given', () => {
+ expect(flattenGuestCartData(undefined)).toBeUndefined();
+ });
+});
+
+describe('#flattenCustomerOrderData', () => {
it('returns flat cart data', () => {
- const expected = {
- city: 'city',
- country: 'country',
- email: 'email',
- firstname: 'firstname',
- lastname: 'lastname',
- postcode: 'postcode',
- region: 'region',
- shippingMethod: 'carrier - method',
- street: ['street'],
- totalItemQuantity: 1
- };
- expect(flatten(mockData)).toEqual(expected);
+ expect(flattenCustomerOrderData(mockCustomerOrderData)).toEqual(
+ expectedFlatData
+ );
+ });
+ it('returns nothing when there is no data given', () => {
+ expect(flattenCustomerOrderData(undefined)).toBeUndefined();
});
});
-it('returns the correct shape', () => {
- const tree = createTestInstance();
+describe('for guest', () => {
+ it('returns the correct shape', () => {
+ useUserContext.mockImplementationOnce(() => {
+ return [
+ {
+ isSignedIn: false
+ }
+ ];
+ });
+ const tree = createTestInstance();
+
+ const { root } = tree;
+ const { talonProps } = root.findByType('i').props;
- const { root } = tree;
- const { talonProps } = root.findByType('i').props;
+ expect(talonProps).toMatchSnapshot();
+ });
+});
- expect(talonProps).toMatchSnapshot();
+describe('for authenticated customers', () => {
+ it('returns the correct shape', () => {
+ const mockFetch = jest.fn();
+
+ useLazyQuery.mockReturnValueOnce([
+ mockFetch,
+ {
+ data: mockCustomerOrderData,
+ error: undefined,
+ loading: false
+ }
+ ]);
+
+ const mockOrderNumber = '12345';
+
+ const tree = createTestInstance(
+
+ );
+
+ const { root } = tree;
+ const { talonProps } = root.findByType('i').props;
+
+ expect(talonProps).toMatchSnapshot();
+
+ expect(mockFetch).toHaveBeenCalledWith({
+ variables: { orderNumber: mockOrderNumber }
+ });
+ });
});
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.gql.js b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.gql.js
new file mode 100644
index 0000000000..4c67d9e7cf
--- /dev/null
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.gql.js
@@ -0,0 +1,30 @@
+import { gql } from '@apollo/client';
+
+export const GET_ORDER_CONFIRMATION_DETAILS = gql`
+ query getOrderConfirmationDetails($orderNumber: String!) {
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
+ customer {
+ email
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
+ orders(filter: { number: { eq: $orderNumber } }) {
+ items {
+ id
+ shipping_address {
+ firstname
+ lastname
+ street
+ city
+ region
+ postcode
+ country_code
+ }
+ shipping_method
+ }
+ }
+ }
+ }
+`;
+
+export default {
+ getOrderConfirmationDetailsQuery: GET_ORDER_CONFIRMATION_DETAILS
+};
diff --git a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
index 31b6430974..2c7f75e185 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage.js
@@ -1,6 +1,14 @@
+import { useEffect } from 'react';
import { useUserContext } from '../../../context/user';
+import { useLazyQuery } from '@apollo/client';
-export const flatten = data => {
+import mergeOperations from '../../../util/shallowMerge';
+import DEFAULT_OPERATIONS from './orderConfirmationPage.gql';
+
+export const flattenGuestCartData = data => {
+ if (!data) {
+ return;
+ }
const { cart } = data;
const { shipping_addresses } = cart;
const address = shipping_addresses[0];
@@ -18,17 +26,60 @@ export const flatten = data => {
postcode: address.postcode,
region: address.region.label,
shippingMethod,
+ street: address.street
+ };
+};
+
+export const flattenCustomerOrderData = data => {
+ if (!data) {
+ return;
+ }
+ const { customer } = data;
+ const order = customer.orders.items[0];
+ const { shipping_address: address } = order;
+
+ return {
+ city: address.city,
+ country: address.country_code,
+ email: customer.email,
+ firstname: address.firstname,
+ lastname: address.lastname,
+ postcode: address.postcode,
+ region: address.region,
street: address.street,
- totalItemQuantity: cart.total_quantity
+ shippingMethod: order.shipping_method
};
};
export const useOrderConfirmationPage = props => {
- const { data } = props;
+ const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
+ const { getOrderConfirmationDetailsQuery } = operations;
+
const [{ isSignedIn }] = useUserContext();
+ const [
+ fetchOrderConfirmationDetails,
+ { data: queryData, error, loading }
+ ] = useLazyQuery(getOrderConfirmationDetailsQuery);
+
+ const flatData =
+ flattenGuestCartData(props.data) || flattenCustomerOrderData(queryData);
+
+ useEffect(() => {
+ if (props.orderNumber && !props.data) {
+ const orderNumber = props.orderNumber;
+ fetchOrderConfirmationDetails({
+ variables: {
+ orderNumber
+ }
+ });
+ }
+ }, [props.orderNumber, props.data, fetchOrderConfirmationDetails]);
+
return {
- flatData: flatten(data),
- isSignedIn
+ flatData,
+ isSignedIn,
+ error,
+ loading
};
};
diff --git a/packages/peregrine/lib/talons/CheckoutPage/__tests__/useCheckoutPage.spec.js b/packages/peregrine/lib/talons/CheckoutPage/__tests__/useCheckoutPage.spec.js
index 216297d2d4..18b3036a0c 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/__tests__/useCheckoutPage.spec.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/__tests__/useCheckoutPage.spec.js
@@ -6,7 +6,7 @@ import {
useQuery
} from '@apollo/client';
import { act } from 'react-test-renderer';
-
+import { useHistory } from 'react-router-dom';
import { useCheckoutPage, CHECKOUT_STEP } from '../useCheckoutPage';
import createTestInstance from '../../../util/createTestInstance';
import { useCartContext } from '../../../context/cart';
@@ -27,6 +27,11 @@ jest.mock('@apollo/client', () => {
useQuery: jest.fn()
};
});
+jest.mock('react-router-dom', () => {
+ return {
+ useHistory: jest.fn()
+ };
+});
jest.mock('react', () => ({
...jest.requireActual('react'),
@@ -158,8 +163,10 @@ const getTalonProps = props => {
/**
* beforeAll
*/
-
+const mockPush = jest.fn(); // Create a mock function for push
+const mockHistory = { push: mockPush };
beforeEach(() => {
+ useHistory.mockReturnValue(mockHistory);
useQuery.mockImplementation(query => {
if (query === getCheckoutDetailsQuery) {
return getCheckoutDetailsQueryResult();
@@ -451,6 +458,7 @@ test('orderDetailsLoading should be loading status of the getOrderDetailsQuery',
});
test('orderNumber should be the order_number from the place order mutation result', () => {
+ useUserContext.mockReturnValueOnce([{ isSignedIn: false }]);
placeOrderMutationResult.mockReturnValueOnce([
() => {},
{
diff --git a/packages/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js b/packages/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js
index e084d05794..d9e99b0978 100644
--- a/packages/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js
+++ b/packages/peregrine/lib/talons/CheckoutPage/useCheckoutPage.js
@@ -7,6 +7,8 @@ import {
} from '@apollo/client';
import { useEventingContext } from '../../context/eventing';
+import { useHistory } from 'react-router-dom';
+
import { useUserContext } from '../../context/user';
import { useCartContext } from '../../context/cart';
@@ -68,8 +70,8 @@ export const CHECKOUT_STEP = {
* }
*/
export const useCheckoutPage = (props = {}) => {
+ const history = useHistory();
const operations = mergeOperations(DEFAULT_OPERATIONS, props.operations);
-
const {
createCartMutation,
getCheckoutDetailsQuery,
@@ -249,6 +251,7 @@ export const useCheckoutPage = (props = {}) => {
});
setPlaceOrderButtonClicked(true);
setIsPlacingOrder(true);
+ localStorage.setItem('orderCount', '1');
}, [cartId, getOrderDetails]);
const handlePlaceOrderEnterKeyPress = useCallback(() => {
@@ -383,6 +386,16 @@ export const useCheckoutPage = (props = {}) => {
isPlacingOrder,
reviewOrderButtonClicked
]);
+ useEffect(() => {
+ if (isSignedIn && placeOrderData) {
+ history.push('/order-confirmation', {
+ orderNumber: placeOrderData.placeOrder.order.order_number,
+ items: cartItems
+ });
+ } else if (!isSignedIn && placeOrderData) {
+ history.push('/checkout');
+ }
+ }, [isSignedIn, placeOrderData, cartItems, history]);
return {
activeContent,
diff --git a/packages/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js b/packages/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js
index ea3f1a75b6..0a2cb13b72 100644
--- a/packages/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js
+++ b/packages/venia-ui/lib/components/CheckoutPage/ItemsReview/itemsReview.js
@@ -5,7 +5,6 @@ import { useItemsReview } from '@magento/peregrine/lib/talons/CheckoutPage/Items
import Item from './item';
import ShowAllButton from './showAllButton';
-import LoadingIndicator from '../../LoadingIndicator';
import { useStyle } from '../../../classify';
import defaultClasses from './itemsReview.module.css';
@@ -19,16 +18,13 @@ const ItemsReview = props => {
const classes = useStyle(defaultClasses, propClasses);
- const talonProps = useItemsReview({
- data: props.data
- });
+ const talonProps = useItemsReview(props);
const {
items: itemsInCart,
totalQuantity,
showAllItems,
setShowAllItems,
- isLoading,
configurableThumbnailSource
} = talonProps;
@@ -45,17 +41,6 @@ const ItemsReview = props => {
) : null;
- if (isLoading) {
- return (
-
-
-
- );
- }
-
return (
-
+
`;
+
+exports[`OrderConfirmationPage renders component using location state when there are no props provided 1`] = `
+
+ Title
+
+
+
+
+
+
+
+
+
+
+
+
+ badvirus@covid.com
+
+
+ Stuck Indoors
+
+
+ 123 Stir Crazy Dr.
+
+
+ Austin, TX 91111 US
+
+
+
+
+
+
+ Flat Rate - Fixed
+
+
+
+
+
+
+
+
+
+
+`;
diff --git a/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/orderConfirmationPage.spec.js b/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/orderConfirmationPage.spec.js
index 6e0e76ae6e..5811a0f908 100644
--- a/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/orderConfirmationPage.spec.js
+++ b/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/__tests__/orderConfirmationPage.spec.js
@@ -5,6 +5,9 @@ import { useOrderConfirmationPage } from '@magento/peregrine/lib/talons/Checkout
import OrderConfirmationPage from '../orderConfirmationPage';
import CreateAccount from '../createAccount';
+import { useLocation } from 'react-router-dom';
+import cartItems from '../__fixtures__/cartItems';
+
jest.mock('@magento/peregrine', () => {
const actual = jest.requireActual('@magento/peregrine');
const useToasts = jest.fn().mockReturnValue([{}, { addToast: jest.fn() }]);
@@ -27,6 +30,12 @@ jest.mock('../../../../components/Head', () => ({ StoreTitle: () => 'Title' }));
jest.mock('../createAccount', () => 'CreateAccount');
jest.mock('../../ItemsReview', () => 'ItemsReview');
+jest.mock('react-router-dom', () => {
+ return {
+ useLocation: jest.fn().mockReturnValue(jest.fn())
+ };
+});
+
const defaultTalonProps = {
flatData: {
city: 'Austin',
@@ -46,23 +55,51 @@ describe('OrderConfirmationPage', () => {
beforeEach(() => {
globalThis.scrollTo = jest.fn();
});
+
test('renders OrderConfirmationPage component', () => {
useOrderConfirmationPage.mockReturnValue({
...defaultTalonProps
});
+ const mockData = {
+ cart: {
+ items: cartItems
+ }
+ };
const instance = createTestInstance(
-
+
);
expect(instance.toJSON()).toMatchSnapshot();
});
+ test('renders component using location state when there are no props provided', () => {
+ useOrderConfirmationPage.mockReturnValue({
+ ...defaultTalonProps,
+ isSignedIn: true
+ });
+ useLocation.mockReturnValue({
+ state: {
+ orderNumber: 123,
+ items: cartItems
+ }
+ });
+ const instance = createTestInstance(
);
+ expect(instance.toJSON()).toMatchSnapshot();
+ });
+
test('renders CreateAccount view if not signed in', () => {
useOrderConfirmationPage.mockReturnValueOnce({
...defaultTalonProps,
- isDisabled: true
+ isSignedIn: false
});
+ const mockData = {
+ cart: {
+ items: cartItems
+ }
+ };
- const instance = createTestInstance(
);
+ const instance = createTestInstance(
+
+ );
const component = instance.root.findByType(CreateAccount);
expect(component).toBeTruthy();
diff --git a/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.js b/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.js
index 369c6e4012..eaeae5867e 100644
--- a/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.js
+++ b/packages/venia-ui/lib/components/CheckoutPage/OrderConfirmationPage/orderConfirmationPage.js
@@ -3,6 +3,8 @@ import { FormattedMessage, useIntl } from 'react-intl';
import { object, shape, string } from 'prop-types';
import { useOrderConfirmationPage } from '@magento/peregrine/lib/talons/CheckoutPage/OrderConfirmationPage/useOrderConfirmationPage';
+import { useLocation } from 'react-router-dom';
+import { fullPageLoadingIndicator } from '../../LoadingIndicator';
import { useStyle } from '../../../classify';
import { StoreTitle } from '../../../components/Head';
import CreateAccount from './createAccount';
@@ -11,34 +13,19 @@ import defaultClasses from './orderConfirmationPage.module.css';
const OrderConfirmationPage = props => {
const classes = useStyle(defaultClasses, props.classes);
- const { data, orderNumber } = props;
+ const location = useLocation();
+ const data = props.data;
+ const orderNumber = props.orderNumber || location.state.orderNumber;
+ const cartItems = data ? data.cart.items : location.state.items;
+
const { formatMessage } = useIntl();
const talonProps = useOrderConfirmationPage({
- data
+ data,
+ orderNumber
});
- const { flatData, isSignedIn } = talonProps;
-
- const {
- city,
- country,
- email,
- firstname,
- lastname,
- postcode,
- region,
- shippingMethod,
- street
- } = flatData;
-
- const streetRows = street.map((row, index) => {
- return (
-
- {row}
-
- );
- });
+ const { flatData, isSignedIn, loading } = talonProps;
useEffect(() => {
const { scrollTo } = globalThis;
@@ -52,90 +39,118 @@ const OrderConfirmationPage = props => {
}
}, []);
- const createAccountForm = !isSignedIn ? (
-
- ) : null;
+ if (!flatData || loading) {
+ return fullPageLoadingIndicator;
+ } else {
+ const {
+ city,
+ country,
+ email,
+ firstname,
+ lastname,
+ postcode,
+ region,
+ shippingMethod,
+ street
+ } = flatData;
- const nameString = `${firstname} ${lastname}`;
- const additionalAddressString = `${city}, ${region} ${postcode} ${country}`;
+ const streetRows = street.map((row, index) => {
+ return (
+
+ {row}
+
+ );
+ });
- return (
-
-
- {formatMessage({
- id: 'checkoutPage.titleReceipt',
- defaultMessage: 'Receipt'
- })}
-
-
-
-
-
-
-
-
-
-
-
-
- {email}
- {nameString}
- {streetRows}
-
- {additionalAddressString}
-
-
-
-
-
-
{shippingMethod}
-
-
+ const createAccountForm = !isSignedIn ? (
+
+ ) : null;
+
+ const nameString = `${firstname} ${lastname}`;
+ const additionalAddressString = `${city}, ${region} ${postcode} ${country}`;
+
+ return (
+
+
+ {formatMessage({
+ id: 'checkoutPage.titleReceipt',
+ defaultMessage: 'Receipt'
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+ {email}
+ {nameString}
+ {streetRows}
+
+ {additionalAddressString}
+
+
+
+
+
+
+ {shippingMethod}
+
+
+
+
+
+
+
-
-
+
+ {createAccountForm}
-
{createAccountForm}
-
- );
+ );
+ }
};
export default OrderConfirmationPage;
@@ -157,6 +172,6 @@ OrderConfirmationPage.propTypes = {
additionalText: string,
sidebarContainer: string
}),
- data: object.isRequired,
+ data: object,
orderNumber: string
};
diff --git a/packages/venia-ui/lib/components/CheckoutPage/checkoutPage.js b/packages/venia-ui/lib/components/CheckoutPage/checkoutPage.js
index cb319f4d5f..0dba1ba255 100644
--- a/packages/venia-ui/lib/components/CheckoutPage/checkoutPage.js
+++ b/packages/venia-ui/lib/components/CheckoutPage/checkoutPage.js
@@ -2,14 +2,13 @@ import React, { Fragment, useEffect } from 'react';
import { shape, string } from 'prop-types';
import { FormattedMessage, useIntl } from 'react-intl';
import { AlertCircle as AlertCircleIcon } from 'react-feather';
-import { Link } from 'react-router-dom';
+import { Link, useHistory } from 'react-router-dom';
import { useWindowSize, useToasts } from '@magento/peregrine';
import {
CHECKOUT_STEP,
useCheckoutPage
} from '@magento/peregrine/lib/talons/CheckoutPage/useCheckoutPage';
-
import { useStyle } from '../../classify';
import Button from '../Button';
import { StoreTitle } from '../Head';
@@ -25,8 +24,8 @@ import payments from './PaymentInformation/paymentMethodCollection';
import PriceAdjustments from './PriceAdjustments';
import ShippingMethod from './ShippingMethod';
import ShippingInformation from './ShippingInformation';
-import OrderConfirmationPage from './OrderConfirmationPage';
import ItemsReview from './ItemsReview';
+import OrderConfirmationPage from './OrderConfirmationPage';
import GoogleReCaptcha from '../GoogleReCaptcha';
import defaultClasses from './checkoutPage.module.css';
@@ -35,6 +34,7 @@ import ScrollAnchor from '../ScrollAnchor/scrollAnchor';
const errorIcon =
;
const CheckoutPage = props => {
+ const history = useHistory();
const { classes: propClasses } = props;
const { formatMessage } = useIntl();
const talonProps = useCheckoutPage();
@@ -58,8 +58,8 @@ const CheckoutPage = props => {
isGuestCheckout,
isLoading,
isUpdating,
- orderDetailsData,
orderDetailsLoading,
+ orderDetailsData,
orderNumber,
placeOrderLoading,
placeOrderButtonClicked,
@@ -83,7 +83,15 @@ const CheckoutPage = props => {
} = talonProps;
const [, { addToast }] = useToasts();
-
+ const orderCount = localStorage.getItem('orderCount');
+ useEffect(() => {
+ if (isGuestCheckout && !orderDetailsData) {
+ if (orderCount === '1') {
+ history.push('/');
+ localStorage.setItem('orderCount', '0');
+ }
+ }
+ }, [isGuestCheckout, history, orderDetailsData, orderCount]);
useEffect(() => {
if (hasError) {
const message =
@@ -125,7 +133,7 @@ const CheckoutPage = props => {
defaultMessage: 'Checkout'
});
- if (orderNumber && orderDetailsData) {
+ if (isGuestCheckout && orderDetailsData && orderNumber) {
return (
{
const itemsReview =
checkoutStep === CHECKOUT_STEP.REVIEW ? (
-
+
) : null;
diff --git a/packages/venia-ui/lib/defaultRoutes.json b/packages/venia-ui/lib/defaultRoutes.json
index e869dafdb8..3adb4587e7 100644
--- a/packages/venia-ui/lib/defaultRoutes.json
+++ b/packages/venia-ui/lib/defaultRoutes.json
@@ -53,6 +53,12 @@
"exact": true,
"path": "../ForgotPasswordPage"
},
+ {
+ "name": "OrderConfirmation",
+ "pattern": "/order-confirmation",
+ "exact": true,
+ "path": "../CheckoutPage/OrderConfirmationPage"
+ },
{
"name": "OrderHistory",
"pattern": "/order-history",