@magento/peregrine 12.0.0 → 12.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/lib/Apollo/clearCartDataFromCache.js +11 -12
  2. package/lib/Apollo/clearCustomerDataFromCache.js +15 -8
  3. package/lib/Apollo/policies/index.js +35 -3
  4. package/lib/Toasts/useToasts.js +5 -0
  5. package/lib/context/cart.js +21 -1
  6. package/lib/hooks/useCustomerWishlistSkus/customerWishlist.gql.ce.js +3 -3
  7. package/lib/store/actions/cart/asyncActions.js +2 -3
  8. package/lib/store/actions/user/asyncActions.js +2 -4
  9. package/lib/store/reducers/catalog.js +7 -7
  10. package/lib/store/reducers/user.js +1 -3
  11. package/lib/talons/Adapter/useAdapter.js +80 -11
  12. package/lib/talons/AddToCartDialog/addToCartDialog.gql.js +2 -2
  13. package/lib/talons/AddressBookPage/addressBookPage.gql.js +3 -9
  14. package/lib/talons/Breadcrumbs/breadcrumbs.gql.js +16 -12
  15. package/lib/talons/Breadcrumbs/useBreadcrumbs.js +6 -4
  16. package/lib/talons/CartPage/GiftCards/giftCardQueries.gql.ee.js +2 -2
  17. package/lib/talons/CartPage/PriceAdjustments/CouponCode/couponCode.gql.js +2 -3
  18. package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/shippingMethods.gql.js +1 -1
  19. package/lib/talons/CartPage/PriceSummary/priceSummaryFragments.gql.js +2 -1
  20. package/lib/talons/CartPage/ProductListing/EditModal/__fixtures__/configurableProduct.js +1 -0
  21. package/lib/talons/CartPage/ProductListing/EditModal/productForm.gql.js +10 -7
  22. package/lib/talons/CartPage/ProductListing/EditModal/productFormFragment.gql.js +7 -3
  23. package/lib/talons/CartPage/ProductListing/EditModal/useProductForm.js +3 -2
  24. package/lib/talons/CartPage/ProductListing/product.gql.js +2 -1
  25. package/lib/talons/CartPage/ProductListing/productListing.gql.ce.js +2 -1
  26. package/lib/talons/CartPage/ProductListing/productListing.gql.ee.js +2 -1
  27. package/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +15 -5
  28. package/lib/talons/CartPage/ProductListing/useProduct.js +12 -5
  29. package/lib/talons/CartPage/ProductListing/useProductListing.js +4 -2
  30. package/lib/talons/CartPage/useCartPage.js +4 -3
  31. package/lib/talons/CategoryList/categoryList.gql.js +25 -17
  32. package/lib/talons/CategoryList/useCategoryList.js +6 -1
  33. package/lib/talons/CategoryList/useCategoryTile.js +2 -0
  34. package/lib/talons/CategoryTree/categoryTree.gql.js +18 -12
  35. package/lib/talons/CategoryTree/useCategoryBranch.js +1 -1
  36. package/lib/talons/CategoryTree/useCategoryTree.js +5 -5
  37. package/lib/talons/CheckoutPage/AddressBook/addressBook.gql.js +1 -1
  38. package/lib/talons/CheckoutPage/BillingAddress/billingAddress.gql.js +1 -1
  39. package/lib/talons/CheckoutPage/ItemsReview/__fixtures__/cartItems.js +12 -12
  40. package/lib/talons/CheckoutPage/ItemsReview/itemsReview.gql.js +2 -1
  41. package/lib/talons/CheckoutPage/ItemsReview/itemsReviewFragments.gql.js +11 -5
  42. package/lib/talons/CheckoutPage/OrderConfirmationPage/createAccount.gql.js +12 -6
  43. package/lib/talons/CheckoutPage/PaymentInformation/creditCard.gql.js +2 -2
  44. package/lib/talons/CheckoutPage/PaymentInformation/paymentInformation.gql.js +2 -2
  45. package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/customerForm.gql.js +3 -5
  46. package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/guestForm.gql.js +12 -4
  47. package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/useGuestForm.js +45 -5
  48. package/lib/talons/CheckoutPage/ShippingInformation/shippingInformation.gql.js +2 -2
  49. package/lib/talons/CheckoutPage/ShippingMethod/shippingMethod.gql.js +1 -1
  50. package/lib/talons/CheckoutPage/checkoutPage.gql.js +2 -2
  51. package/lib/talons/CheckoutPage/checkoutPageFragments.gql.js +4 -2
  52. package/lib/talons/CheckoutPage/useCheckoutPage.js +5 -2
  53. package/lib/talons/Cms/cmsPage.gql.js +0 -4
  54. package/lib/talons/Cms/useCmsPage.js +6 -23
  55. package/lib/talons/CommunicationsPage/communicationsPage.gql.js +2 -2
  56. package/lib/talons/ContactPage/contactUs.gql.js +48 -0
  57. package/lib/talons/ContactPage/index.js +2 -0
  58. package/lib/talons/ContactPage/useContactLink.js +27 -0
  59. package/lib/talons/ContactPage/useContactPage.js +85 -0
  60. package/lib/talons/CreateAccount/createAccount.gql.js +15 -8
  61. package/lib/talons/CreateAccount/useCreateAccount.js +2 -4
  62. package/lib/talons/Footer/footer.gql.js +2 -1
  63. package/lib/talons/FormError/useFormError.js +9 -7
  64. package/lib/talons/Gallery/__fixtures__/apolloMocks.js +2 -2
  65. package/lib/talons/Gallery/gallery.gql.ce.js +2 -1
  66. package/lib/talons/Gallery/gallery.gql.ee.js +2 -1
  67. package/lib/talons/Gallery/useAddToCartButton.js +28 -13
  68. package/lib/talons/Header/storeSwitcher.gql.js +21 -9
  69. package/lib/talons/Header/useCartTrigger.js +3 -3
  70. package/lib/talons/Header/useStoreSwitcher.js +10 -8
  71. package/lib/talons/MagentoRoute/magentoRoute.gql.js +4 -2
  72. package/lib/talons/MagentoRoute/useMagentoRoute.js +39 -33
  73. package/lib/talons/MegaMenu/megaMenu.gql.js +10 -5
  74. package/lib/talons/MegaMenu/useMegaMenu.js +3 -5
  75. package/lib/talons/MegaMenu/useMegaMenuItem.js +5 -0
  76. package/lib/talons/MiniCart/ProductList/productListFragments.gql.js +11 -5
  77. package/lib/talons/MiniCart/miniCart.gql.js +2 -1
  78. package/lib/talons/MiniCart/useItem.js +3 -3
  79. package/lib/talons/MiniCart/useMiniCart.js +8 -7
  80. package/lib/talons/Navigation/navigation.gql.js +4 -3
  81. package/lib/talons/Navigation/useNavigation.js +1 -1
  82. package/lib/talons/Newsletter/newsletter.gql.js +24 -0
  83. package/lib/talons/Newsletter/useNewsletter.js +70 -0
  84. package/lib/talons/OrderHistoryPage/orderHistoryContext.gql.js +2 -1
  85. package/lib/talons/OrderHistoryPage/orderHistoryPage.gql.js +1 -1
  86. package/lib/talons/OrderHistoryPage/orderRow.gql.js +7 -3
  87. package/lib/talons/ProductFullDetail/CustomAttributes/AttributeType/useAttributeType.js +26 -0
  88. package/lib/talons/ProductFullDetail/productFullDetail.gql.ce.js +4 -3
  89. package/lib/talons/ProductFullDetail/productFullDetail.gql.ee.js +2 -1
  90. package/lib/talons/ProductFullDetail/useProductFullDetail.js +35 -3
  91. package/lib/talons/RootComponents/Category/category.gql.js +7 -4
  92. package/lib/talons/RootComponents/Category/categoryContent.gql.js +26 -7
  93. package/lib/talons/RootComponents/Category/categoryFragments.gql.js +5 -2
  94. package/lib/talons/RootComponents/Category/useCategory.js +8 -6
  95. package/lib/talons/RootComponents/Category/useCategoryContent.js +30 -3
  96. package/lib/talons/RootComponents/Category/useNoProductsFound.js +0 -1
  97. package/lib/talons/RootComponents/Product/product.gql.js +3 -1
  98. package/lib/talons/RootComponents/Product/productDetailFragment.gql.js +69 -10
  99. package/lib/talons/SearchPage/searchPage.gql.js +18 -2
  100. package/lib/talons/SearchPage/useSearchPage.js +25 -0
  101. package/lib/talons/SignIn/signIn.gql.js +4 -3
  102. package/lib/talons/SignIn/useSignIn.js +2 -4
  103. package/lib/talons/Wishlist/WishlistDialog/wishlistDialog.gql.js +3 -2
  104. package/lib/talons/WishlistPage/createWishlist.gql.js +2 -1
  105. package/lib/talons/WishlistPage/useWishlistItem.js +2 -2
  106. package/lib/talons/WishlistPage/wishlist.gql.js +2 -2
  107. package/lib/talons/WishlistPage/wishlistConfig.gql.ce.js +2 -1
  108. package/lib/talons/WishlistPage/wishlistConfig.gql.ee.js +2 -1
  109. package/lib/talons/WishlistPage/wishlistItemFragments.gql.js +5 -2
  110. package/lib/talons/WishlistPage/wishlistPage.gql.js +1 -1
  111. package/package.json +6 -6
  112. package/lib/Apollo/clearStore.js +0 -26
  113. package/lib/Apollo/deleteCacheEntry.js +0 -87
@@ -1,19 +1,18 @@
1
- import { deleteCacheEntry } from './deleteCacheEntry';
2
-
3
1
  /**
4
- * Deletes all references to Cart from the apollo cache including entries that
5
- * start with "$" which were automatically created by Apollo InMemoryCache.
2
+ * Deletes all references to Cart from the apollo cache
6
3
  *
7
4
  * @param {ApolloClient} client
8
5
  */
9
6
  export const clearCartDataFromCache = async client => {
10
- await deleteCacheEntry(client, key => key.match(/^\$?Cart/));
7
+ // Cached data
8
+ client.cache.evict({ id: 'Cart' });
9
+ // Cached ROOT_QUERY
10
+ client.cache.evict({ fieldName: 'cart' });
11
+ client.cache.evict({ fieldName: 'customerCart' });
12
+
13
+ client.cache.gc();
11
14
 
12
- // Any cart subtypes that have key fields must be manually cleared.
13
- // TODO: we may be able to use cache.evict here instead.
14
- await deleteCacheEntry(client, key => key.match(/^\$?AppliedGiftCard/));
15
- await deleteCacheEntry(client, key => key.match(/^\$?ShippingCartAddress/));
16
- await deleteCacheEntry(client, key =>
17
- key.match(/^\$?AvailableShippingMethod/)
18
- );
15
+ if (client.persistor) {
16
+ await client.persistor.persist();
17
+ }
19
18
  };
@@ -1,14 +1,21 @@
1
- import { deleteCacheEntry } from './deleteCacheEntry';
2
-
3
1
  /**
4
- * Deletes all references to Customer from the apollo cache including entries
5
- * that start with "$" which were automatically created by Apollo InMemoryCache.
6
- * By coincidence this rule additionally clears CustomerAddress entries, but
7
- * we'll need to keep this in mind by adding additional patterns as MyAccount
8
- * features are completed.
2
+ * Deletes all references to Customer from the apollo cache.
3
+ * Related queries that have reference to the customer are also deleted
4
+ * through the cascade. Note, however, that all secondary references must
5
+ * be deleted in order for garbage collection to do its job.
9
6
  *
10
7
  * @param {ApolloClient} client
11
8
  */
12
9
  export const clearCustomerDataFromCache = async client => {
13
- await deleteCacheEntry(client, key => key.match(/^\$?Customer/i));
10
+ // Cached data
11
+ client.cache.evict({ id: 'Customer' });
12
+ // Cached ROOT_QUERY
13
+ client.cache.evict({ fieldName: 'customer' });
14
+ client.cache.evict({ fieldName: 'customerWishlistProducts' });
15
+
16
+ client.cache.gc();
17
+
18
+ if (client.persistor) {
19
+ await client.persistor.persist();
20
+ }
14
21
  };
@@ -37,8 +37,8 @@ const typePolicies = {
37
37
  keyFields: ['carrier_code', 'method_code']
38
38
  },
39
39
  Breadcrumb: {
40
- // Uses provided fields on the object as the `id`.
41
- keyFields: ['category_id']
40
+ // Uses provided fields on the object as the `uid`.
41
+ keyFields: ['category_uid']
42
42
  },
43
43
  Cart: {
44
44
  keyFields: () => 'Cart',
@@ -109,6 +109,7 @@ const typePolicies = {
109
109
  },
110
110
  Customer: {
111
111
  keyFields: () => 'Customer',
112
+ merge: true,
112
113
  fields: {
113
114
  addresses: {
114
115
  merge(existing, incoming) {
@@ -164,13 +165,22 @@ const typePolicies = {
164
165
  }
165
166
  }
166
167
  },
168
+ Currency: {
169
+ merge: true
170
+ },
167
171
  ProductImage: {
168
172
  keyFields: ['url']
169
173
  },
174
+ ConfigurableProductOptions: {
175
+ keyFields: ['uid']
176
+ },
170
177
  SelectedConfigurableOption: {
171
178
  // id alone is not enough to identify a selected option as it can refer
172
179
  // to something like "size" where value_id refers to "large".
173
- keyFields: ['id', 'value_id']
180
+ keyFields: [
181
+ 'configurable_product_option_uid',
182
+ 'configurable_product_option_value_uid'
183
+ ]
174
184
  },
175
185
  SelectedPaymentMethod: {
176
186
  keyFields: ['code']
@@ -240,6 +250,7 @@ const typePolicies = {
240
250
  }
241
251
  },
242
252
  CategoryTree: {
253
+ keyFields: ['uid'],
243
254
  fields: {
244
255
  children: {
245
256
  merge(existing, incoming) {
@@ -298,6 +309,27 @@ const typePolicies = {
298
309
  },
299
310
  GiftCardWishlistItem: {
300
311
  keyFields: ({ id }) => `CustomerGiftCardWishlistItem:${id}`
312
+ },
313
+ SimpleProduct: {
314
+ keyFields: ['uid']
315
+ },
316
+ ConfigurableProduct: {
317
+ keyFields: ['uid']
318
+ },
319
+ BundleProduct: {
320
+ keyFields: ['uid']
321
+ },
322
+ GroupedProduct: {
323
+ keyFields: ['uid']
324
+ },
325
+ VirtualProduct: {
326
+ keyFields: ['uid']
327
+ },
328
+ CartItemInterface: {
329
+ keyFields: ['uid']
330
+ },
331
+ StoreConfig: {
332
+ keyFields: ['store_code']
301
333
  }
302
334
  };
303
335
 
@@ -100,6 +100,11 @@ export const useToasts = () => {
100
100
  * This property is optional when creating toasts.
101
101
  * @property {String} [actionText] Text to display as a call to action.
102
102
  * This property is optional when creating toasts.
103
+ * @property {Bool} [hasDismissAction] Indicates whether the toast should have a
104
+ * dismiss action with the same behavior as the dismiss icon.
105
+ * This property is optional when creating toasts.
106
+ * @property {String} [dismissActionText] Text to display as a call to dissmisAction.
107
+ * This property is optional when creating toasts.
103
108
  * @property {Function} [onAction] Callback invoked when a user clicks the action
104
109
  * text.
105
110
  * This property is optional when creating toasts.
@@ -1,4 +1,10 @@
1
- import React, { createContext, useContext, useEffect, useMemo } from 'react';
1
+ import React, {
2
+ createContext,
3
+ useContext,
4
+ useEffect,
5
+ useMemo,
6
+ useCallback
7
+ } from 'react';
2
8
  import { connect } from 'react-redux';
3
9
  import { useMutation } from '@apollo/client';
4
10
  import gql from 'graphql-tag';
@@ -7,6 +13,8 @@ import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
7
13
  import actions from '../store/actions/cart/actions';
8
14
  import * as asyncActions from '../store/actions/cart/asyncActions';
9
15
  import bindActionCreators from '../util/bindActionCreators';
16
+ import { useEventListener } from '../hooks/useEventListener';
17
+ import BrowserPersistence from '../util/simplePersistence';
10
18
 
11
19
  const CartContext = createContext();
12
20
 
@@ -57,6 +65,18 @@ const CartContextProvider = props => {
57
65
  const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
58
66
  const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
59
67
 
68
+ // Storage listener to force a state update if cartId changes from another browser tab.
69
+ const storageListener = useCallback(() => {
70
+ const storage = new BrowserPersistence();
71
+ const currentCartId = storage.getItem('cartId');
72
+ const { cartId } = cartState;
73
+ if (cartId && currentCartId && cartId !== currentCartId) {
74
+ globalThis.location && globalThis.location.reload();
75
+ }
76
+ }, [cartState]);
77
+
78
+ useEventListener(globalThis, 'storage', storageListener);
79
+
60
80
  useEffect(() => {
61
81
  // cartApi.getCartDetails initializes the cart if there isn't one.
62
82
  cartApi.getCartDetails({
@@ -1,18 +1,18 @@
1
1
  import { gql } from '@apollo/client';
2
-
3
2
  import { GET_PRODUCTS_IN_WISHLISTS } from '@magento/peregrine/lib/talons/Wishlist/AddToListButton/addToListButton.gql';
4
3
 
5
4
  export const GET_WISHLIST_ITEMS = gql`
6
5
  query GetWishlistItemsForLocalField($currentPage: Int!) {
6
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
7
7
  customer {
8
- id
9
8
  wishlists {
10
9
  id
11
10
  items_v2(currentPage: $currentPage, pageSize: 10) {
12
11
  items {
13
12
  id
13
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
14
14
  product {
15
- id
15
+ uid
16
16
  sku
17
17
  }
18
18
  }
@@ -1,4 +1,3 @@
1
- import { clearCartDataFromCache } from '../../../Apollo/clearCartDataFromCache';
2
1
  import BrowserPersistence from '../../../util/simplePersistence';
3
2
  import { signOut } from '../user';
4
3
  import actions from './actions';
@@ -276,7 +275,7 @@ export const removeItemFromCart = payload => {
276
275
  await removeItem({
277
276
  variables: {
278
277
  cartId,
279
- itemId: item.id
278
+ itemId: item.uid
280
279
  }
281
280
  });
282
281
 
@@ -368,7 +367,7 @@ export const getCartDetails = payload => {
368
367
  }
369
368
 
370
369
  // Clear cart data from Apollo cache
371
- await clearCartDataFromCache(apolloClient);
370
+ await apolloClient.clearCacheData(apolloClient, 'cart');
372
371
 
373
372
  // Create a new cart
374
373
  try {
@@ -1,6 +1,4 @@
1
1
  import BrowserPersistence from '../../../util/simplePersistence';
2
- import { clearCartDataFromCache } from '../../../Apollo/clearCartDataFromCache';
3
- import { clearCustomerDataFromCache } from '../../../Apollo/clearCustomerDataFromCache';
4
2
  import { removeCart } from '../cart';
5
3
  import { clearCheckoutDataFromStorage } from '../checkout';
6
4
 
@@ -25,8 +23,8 @@ export const signOut = (payload = {}) =>
25
23
  await dispatch(clearToken());
26
24
  await dispatch(actions.reset());
27
25
  await clearCheckoutDataFromStorage();
28
- await clearCartDataFromCache(apolloClient);
29
- await clearCustomerDataFromCache(apolloClient);
26
+ await apolloClient.clearCacheData(apolloClient, 'cart');
27
+ await apolloClient.clearCacheData(apolloClient, 'customer');
30
28
 
31
29
  // Now that we're signed out, forget the old (customer) cart.
32
30
  // We don't need to create a new cart here because we're going to refresh
@@ -23,8 +23,8 @@ const initialState = {
23
23
 
24
24
  const reducerMap = {
25
25
  [actions.updateCategories]: (state, { payload }) => {
26
- const { id } = payload;
27
- const currentCategory = state.categories[id] || {};
26
+ const { uid } = payload;
27
+ const currentCategory = state.categories[uid] || {};
28
28
 
29
29
  // if category has already been fetched, do nothing
30
30
  if (currentCategory.children) {
@@ -35,7 +35,7 @@ const reducerMap = {
35
35
  const children = [...payload.children].sort((a, b) => {
36
36
  if (a.position > b.position) {
37
37
  return 1;
38
- } else if (a.position === b.position && a.id > b.id) {
38
+ } else if (a.position === b.position && a.uid > b.uid) {
39
39
  return 1;
40
40
  } else {
41
41
  return -1;
@@ -48,10 +48,10 @@ const reducerMap = {
48
48
 
49
49
  // merge children and add them to the Map, keyed by `id`
50
50
  for (const child of children) {
51
- childMap.set(child.id, {
51
+ childMap.set(child.uid, {
52
52
  ...child,
53
- ...(state.categories[child.id] || {}),
54
- parentId: id
53
+ ...(state.categories[child.uid] || {}),
54
+ parentId: uid
55
55
  });
56
56
  }
57
57
 
@@ -61,7 +61,7 @@ const reducerMap = {
61
61
  categories: {
62
62
  ...state.categories,
63
63
  ...fromPairs(childMap),
64
- [id]: {
64
+ [uid]: {
65
65
  ...currentCategory,
66
66
  ...payload,
67
67
  children: [...childMap.keys()],
@@ -1,7 +1,5 @@
1
1
  import { handleActions } from 'redux-actions';
2
-
3
- import { Util } from '../../index';
4
- const { BrowserPersistence } = Util;
2
+ import BrowserPersistence from '../../util/simplePersistence';
5
3
 
6
4
  const storage = new BrowserPersistence();
7
5
 
@@ -7,10 +7,12 @@ import { RetryLink } from '@apollo/client/link/retry';
7
7
  import { CachePersistor } from 'apollo-cache-persist';
8
8
  import getWithPath from 'lodash.get';
9
9
  import setWithPath from 'lodash.set';
10
- import { useEffect, useMemo, useState, useCallback } from 'react';
10
+ import { useCallback, useEffect, useMemo, useState } from 'react';
11
11
 
12
12
  import MutationQueueLink from '@adobe/apollo-link-mutation-queue';
13
13
  import attachClient from '@magento/peregrine/lib/Apollo/attachClientToStore';
14
+ import { clearCartDataFromCache } from '@magento/peregrine/lib/Apollo/clearCartDataFromCache';
15
+ import { clearCustomerDataFromCache } from '@magento/peregrine/lib/Apollo/clearCustomerDataFromCache';
14
16
  import { CACHE_PERSIST_PREFIX } from '@magento/peregrine/lib/Apollo/constants';
15
17
  import typePolicies from '@magento/peregrine/lib/Apollo/policies';
16
18
  import MagentoGQLCacheLink from '@magento/peregrine/lib/Apollo/magentoGqlCacheLink';
@@ -75,7 +77,8 @@ export const useAdapter = props => {
75
77
  message ===
76
78
  'Some of the products are out of stock.' ||
77
79
  message ===
78
- 'There are no source items with the in stock status'
80
+ 'There are no source items with the in stock status' ||
81
+ message === 'The requested qty is not available'
79
82
  ) {
80
83
  if (!pathToCartItems) {
81
84
  pathToCartItems = path.slice(0, -1);
@@ -187,29 +190,95 @@ export const useAdapter = props => {
187
190
  ]
188
191
  );
189
192
 
190
- const apolloClient = useMemo(() => {
191
- const storeCode = storage.getItem('store_view_code') || 'default';
192
-
193
- const client = new ApolloClient({
194
- cache: preInstantiatedCache,
195
- link: apolloLink,
193
+ const createApolloClient = useCallback((cache, link) => {
194
+ return new ApolloClient({
195
+ cache,
196
+ link,
196
197
  ssrMode: isServer
197
198
  });
199
+ }, []);
198
200
 
199
- const persistor = isServer
201
+ const createCachePersistor = useCallback((storeCode, cache) => {
202
+ return isServer
200
203
  ? null
201
204
  : new CachePersistor({
202
205
  key: `${CACHE_PERSIST_PREFIX}-${storeCode}`,
203
- cache: preInstantiatedCache,
206
+ cache,
204
207
  storage: globalThis.localStorage,
205
208
  debug: process.env.NODE_ENV === 'development'
206
209
  });
210
+ }, []);
211
+
212
+ const clearCacheData = useCallback(
213
+ async (client, cacheType) => {
214
+ const storeCode = storage.getItem('store_view_code') || 'default';
215
+
216
+ // Clear current store
217
+ if (cacheType === 'cart') {
218
+ await clearCartDataFromCache(client);
219
+ } else if (cacheType === 'customer') {
220
+ await clearCustomerDataFromCache(client);
221
+ }
222
+
223
+ // Clear other stores
224
+ for (const store of AVAILABLE_STORE_VIEWS) {
225
+ if (store.code !== storeCode) {
226
+ // Get saved data directly from local storage
227
+ const existingStorePersistor = globalThis.localStorage.getItem(
228
+ `${CACHE_PERSIST_PREFIX}-${store.code}`
229
+ );
230
+
231
+ // Make sure we have data available
232
+ if (
233
+ existingStorePersistor &&
234
+ Object.keys(existingStorePersistor).length > 0
235
+ ) {
236
+ const storeCache = new InMemoryCache();
237
+
238
+ // Restore available data
239
+ storeCache.restore(JSON.parse(existingStorePersistor));
240
+
241
+ const storeClient = createApolloClient(
242
+ storeCache,
243
+ apolloLink
244
+ );
245
+
246
+ storeClient.persistor = isServer
247
+ ? null
248
+ : createCachePersistor(store.code, storeCache);
249
+
250
+ // Clear other store
251
+ if (cacheType === 'cart') {
252
+ await clearCartDataFromCache(storeClient);
253
+ } else if (cacheType === 'customer') {
254
+ await clearCustomerDataFromCache(storeClient);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ },
260
+ [apolloLink, createApolloClient, createCachePersistor]
261
+ );
262
+
263
+ const apolloClient = useMemo(() => {
264
+ const storeCode = storage.getItem('store_view_code') || 'default';
265
+ const client = createApolloClient(preInstantiatedCache, apolloLink);
266
+ const persistor = isServer
267
+ ? null
268
+ : createCachePersistor(storeCode, preInstantiatedCache);
207
269
 
208
270
  client.apiBase = apiBase;
209
271
  client.persistor = persistor;
272
+ client.clearCacheData = clearCacheData;
210
273
 
211
274
  return client;
212
- }, [apiBase, apolloLink]);
275
+ }, [
276
+ apiBase,
277
+ apolloLink,
278
+ clearCacheData,
279
+ createApolloClient,
280
+ createCachePersistor
281
+ ]);
213
282
 
214
283
  const getUserConfirmation = useCallback(async (message, callback) => {
215
284
  if (typeof globalThis.handleRouteChangeConfirmation === 'function') {
@@ -1,7 +1,6 @@
1
1
  import { gql } from '@apollo/client';
2
2
  import { CartTriggerFragment } from '../Header/cartTriggerFragments.gql';
3
3
  import { MiniCartFragment } from '../MiniCart/miniCartFragments.gql';
4
-
5
4
  const GET_PRODUCT_DETAIL = gql`
6
5
  query GetProductDetailForATCDialog(
7
6
  $sku: String!
@@ -24,8 +23,9 @@ const GET_PRODUCT_DETAIL = gql`
24
23
  }
25
24
  }
26
25
  ... on ConfigurableProduct {
26
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
27
27
  configurable_options {
28
- id
28
+ uid
29
29
  attribute_uid
30
30
  label
31
31
  position
@@ -4,8 +4,8 @@ import { CustomerAddressBookAddressFragment } from './addressBookFragments.gql';
4
4
 
5
5
  export const GET_CUSTOMER_ADDRESSES = gql`
6
6
  query GetCustomerAddressesForAddressBook {
7
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
7
8
  customer {
8
- id
9
9
  addresses {
10
10
  id
11
11
  ...CustomerAddressBookAddressFragment
@@ -19,16 +19,11 @@ export const GET_CUSTOMER_ADDRESSES = gql`
19
19
  ${CustomerAddressBookAddressFragment}
20
20
  `;
21
21
 
22
- /**
23
- * We use the connection key directive here because Apollo will save
24
- * this customer's PII in localStorage if not.
25
- */
26
22
  export const ADD_NEW_CUSTOMER_ADDRESS = gql`
27
23
  mutation AddNewCustomerAddressToAddressBook(
28
24
  $address: CustomerAddressInput!
29
25
  ) {
30
- createCustomerAddress(input: $address)
31
- @connection(key: "createCustomerAddress") {
26
+ createCustomerAddress(input: $address) {
32
27
  # We don't manually write to the cache to update the collection
33
28
  # after adding a new address so there's no need to query for a bunch
34
29
  # of address fields here. We use refetchQueries to refresh the list.
@@ -42,8 +37,7 @@ export const UPDATE_CUSTOMER_ADDRESS = gql`
42
37
  $addressId: Int!
43
38
  $updated_address: CustomerAddressInput!
44
39
  ) {
45
- updateCustomerAddress(id: $addressId, input: $updated_address)
46
- @connection(key: "updateCustomerAddress") {
40
+ updateCustomerAddress(id: $addressId, input: $updated_address) {
47
41
  id
48
42
  ...CustomerAddressBookAddressFragment
49
43
  }
@@ -2,26 +2,30 @@ import { gql } from '@apollo/client';
2
2
 
3
3
  export const GET_STORE_CONFIG_DATA = gql`
4
4
  query GetStoreConfigForBreadcrumbs {
5
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
5
6
  storeConfig {
6
- id
7
+ store_code
7
8
  category_url_suffix
8
9
  }
9
10
  }
10
11
  `;
11
12
 
12
13
  export const GET_BREADCRUMBS = gql`
13
- query GetBreadcrumbs($category_id: Int!) {
14
- category(id: $category_id) {
15
- breadcrumbs {
16
- category_id
17
- # We may not need level if \`breadcrumbs\` is sorted.
18
- category_level
19
- category_name
20
- category_url_path
14
+ query GetBreadcrumbs($category_id: String!) {
15
+ categories(filters: { category_uid: { in: [$category_id] } }) {
16
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
17
+ items {
18
+ breadcrumbs {
19
+ category_uid
20
+ # We may not need level if \`breadcrumbs\` is sorted.
21
+ category_level
22
+ category_name
23
+ category_url_path
24
+ }
25
+ uid
26
+ name
27
+ url_path
21
28
  }
22
- id
23
- name
24
- url_path
25
29
  }
26
30
  }
27
31
  `;
@@ -12,7 +12,7 @@ const sortCrumbs = (a, b) => a.category_level > b.category_level;
12
12
  // Generates the path for the category.
13
13
  const getPath = (path, suffix) => {
14
14
  if (path) {
15
- return `/${path}${suffix}`;
15
+ return `/${path}${suffix || ''}`;
16
16
  }
17
17
 
18
18
  // If there is no path this is just a dead link.
@@ -58,7 +58,7 @@ export const useBreadcrumbs = props => {
58
58
  // When we have breadcrumb data sort and normalize it for easy rendering.
59
59
  const normalizedData = useMemo(() => {
60
60
  if (!loading && data) {
61
- const breadcrumbData = data.category.breadcrumbs;
61
+ const breadcrumbData = data.categories.items[0].breadcrumbs;
62
62
 
63
63
  return (
64
64
  breadcrumbData &&
@@ -79,9 +79,11 @@ export const useBreadcrumbs = props => {
79
79
  const { setShimmerType } = useInternalLink('category');
80
80
 
81
81
  return {
82
- currentCategory: (data && data.category.name) || '',
82
+ currentCategory: (data && data.categories.items[0].name) || '',
83
83
  currentCategoryPath:
84
- (data && `${data.category.url_path}${categoryUrlSuffix || ''}`) ||
84
+ (data &&
85
+ `${data.categories.items[0].url_path}${categoryUrlSuffix ||
86
+ ''}`) ||
85
87
  '#',
86
88
  isLoading: loading,
87
89
  hasError: !!error,
@@ -31,7 +31,7 @@ const APPLY_GIFT_CARD_MUTATION = gql`
31
31
  mutation applyGiftCardToCart($cartId: String!, $giftCardCode: String!) {
32
32
  applyGiftCardToCart(
33
33
  input: { cart_id: $cartId, gift_card_code: $giftCardCode }
34
- ) @connection(key: "applyGiftCardToCart") {
34
+ ) {
35
35
  cart {
36
36
  id
37
37
  ...CartPageFragment
@@ -50,7 +50,7 @@ const REMOVE_GIFT_CARD_MUTATION = gql`
50
50
  mutation removeGiftCard($cartId: String!, $giftCardCode: String!) {
51
51
  removeGiftCardFromCart(
52
52
  input: { cart_id: $cartId, gift_card_code: $giftCardCode }
53
- ) @connection(key: "removeGiftCardFromCart") {
53
+ ) {
54
54
  cart {
55
55
  id
56
56
  ...CartPageFragment
@@ -16,7 +16,7 @@ const APPLY_COUPON_MUTATION = gql`
16
16
  mutation applyCouponToCart($cartId: String!, $couponCode: String!) {
17
17
  applyCouponToCart(
18
18
  input: { cart_id: $cartId, coupon_code: $couponCode }
19
- ) @connection(key: "applyCouponToCart") {
19
+ ) {
20
20
  cart {
21
21
  id
22
22
  ...CartPageFragment
@@ -33,8 +33,7 @@ const APPLY_COUPON_MUTATION = gql`
33
33
 
34
34
  const REMOVE_COUPON_MUTATION = gql`
35
35
  mutation removeCouponFromCart($cartId: String!) {
36
- removeCouponFromCart(input: { cart_id: $cartId })
37
- @connection(key: "removeCouponFromCart") {
36
+ removeCouponFromCart(input: { cart_id: $cartId }) {
38
37
  cart {
39
38
  id
40
39
  ...CartPageFragment
@@ -23,7 +23,7 @@ const SET_SHIPPING_ADDRESS_MUTATION = gql`
23
23
  cart_id: $cartId
24
24
  shipping_addresses: [{ address: $address }]
25
25
  }
26
- ) @connection(key: "setShippingAddressesOnCart") {
26
+ ) {
27
27
  cart {
28
28
  id
29
29
  ...CartPageFragment
@@ -17,8 +17,9 @@ export const GrandTotalFragment = gql`
17
17
  export const PriceSummaryFragment = gql`
18
18
  fragment PriceSummaryFragment on Cart {
19
19
  id
20
+ # eslint-disable-next-line @graphql-eslint/require-id-when-available
20
21
  items {
21
- id
22
+ uid
22
23
  quantity
23
24
  }
24
25
  ...ShippingSummaryFragment
@@ -82,6 +82,7 @@ export const configurableItemResponse = {
82
82
  export const cartItem = {
83
83
  configurable_options: [{ id: 123, value_id: 1 }, { id: 456, value_id: 1 }],
84
84
  id: 123,
85
+ uid: 'NDA=',
85
86
  product: {
86
87
  sku: 'SP01'
87
88
  },