@magento/peregrine 12.4.0-alpha.1 → 12.5.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.
- package/lib/Apollo/links/authLink.js +19 -0
- package/lib/Apollo/links/errorLink.js +64 -0
- package/lib/Apollo/links/gqlCacheLink.js +63 -0
- package/lib/Apollo/links/index.js +66 -0
- package/lib/Apollo/links/mutationQueueLink.js +5 -0
- package/lib/Apollo/links/retryLink.js +17 -0
- package/lib/Apollo/links/storeLink.js +22 -0
- package/lib/Apollo/magentoGqlCacheLink.js +3 -59
- package/lib/PeregrineContextProvider/peregrineContextProvider.js +2 -0
- package/lib/context/eventing.js +57 -0
- package/lib/hooks/useDelayedTransition.js +1 -1
- package/lib/talons/AccountInformationPage/useAccountInformationPage.js +15 -1
- package/lib/talons/Adapter/useAdapter.js +23 -200
- package/lib/talons/AddToCartDialog/addToCartDialog.gql.js +8 -0
- package/lib/talons/AddToCartDialog/useAddToCartDialog.js +46 -2
- package/lib/talons/AddressBookPage/useAddressBookPage.js +52 -17
- package/lib/talons/AuthModal/useAuthModal.js +12 -2
- package/lib/talons/Breadcrumbs/useBreadcrumbs.js +7 -2
- package/lib/talons/CartPage/ProductListing/EditModal/__fixtures__/configurableProduct.js +39 -4
- package/lib/talons/CartPage/ProductListing/EditModal/useProductForm.js +47 -3
- package/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +6 -0
- package/lib/talons/CartPage/ProductListing/useProduct.js +49 -3
- package/lib/talons/CartPage/useCartPage.js +15 -0
- package/lib/talons/CheckoutPage/ItemsReview/itemsReviewFragments.gql.js +12 -14
- package/lib/talons/CheckoutPage/OrderConfirmationPage/orderConfirmationPageFragments.gql.js +21 -1
- package/lib/talons/CheckoutPage/OrderConfirmationPage/useCreateAccount.js +15 -1
- package/lib/talons/CheckoutPage/PaymentInformation/useEditModal.js +10 -1
- package/lib/talons/CheckoutPage/PaymentInformation/usePaymentInformation.js +14 -0
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/useCustomerForm.js +38 -1
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/useGuestForm.js +15 -1
- package/lib/talons/CheckoutPage/ShippingInformation/useShippingInformation.js +13 -0
- package/lib/talons/CheckoutPage/ShippingMethod/useShippingMethod.js +28 -6
- package/lib/talons/CheckoutPage/checkoutPage.gql.js +3 -0
- package/lib/talons/CheckoutPage/useCheckoutPage.js +79 -3
- package/lib/talons/Cms/useCmsPage.js +14 -0
- package/lib/talons/CreateAccount/useCreateAccount.js +15 -1
- package/lib/talons/FilterModal/helpers.js +8 -2
- package/lib/talons/FilterModal/useFilterModal.js +1 -0
- package/lib/talons/FilterSidebar/useFilterSidebar.js +1 -0
- package/lib/talons/Gallery/useAddToCartButton.js +24 -12
- package/lib/talons/Gallery/useGalleryItem.js +85 -1
- package/lib/talons/Header/storeSwitcher.gql.js +1 -16
- package/lib/talons/Header/useAccountMenu.js +21 -2
- package/lib/talons/Header/useStoreSwitcher.js +40 -93
- package/lib/talons/MagentoRoute/useMagentoRoute.js +7 -7
- package/lib/talons/MiniCart/ProductList/productListFragments.gql.js +4 -0
- package/lib/talons/MiniCart/useMiniCart.js +46 -3
- package/lib/talons/ProductFullDetail/useProductFullDetail.js +37 -9
- package/lib/talons/RootComponents/Category/categoryContent.gql.js +2 -0
- package/lib/talons/RootComponents/Category/categoryFragments.gql.js +7 -0
- package/lib/talons/RootComponents/Category/useCategory.js +4 -1
- package/lib/talons/RootComponents/Category/useCategoryContent.js +35 -13
- package/lib/talons/RootComponents/Product/productDetailFragment.gql.js +6 -0
- package/lib/talons/RootComponents/Product/useProduct.js +27 -0
- package/lib/talons/SearchBar/index.js +1 -0
- package/lib/talons/SearchBar/useAutocomplete.js +18 -1
- package/lib/talons/SearchBar/useSuggestedProduct.js +99 -0
- package/lib/talons/SearchPage/searchPage.gql.js +7 -0
- package/lib/talons/SearchPage/useSearchPage.js +56 -28
- package/lib/talons/SignIn/useSignIn.js +19 -2
- package/lib/talons/WishlistPage/useWishlistItem.js +36 -1
- package/lib/talons/WishlistPage/wishlistItemFragments.gql.js +3 -0
- package/lib/util/makeUrl.js +1 -1
- package/package.json +5 -4
|
@@ -1,194 +1,41 @@
|
|
|
1
|
-
import { ApolloLink
|
|
1
|
+
import { ApolloLink } from '@apollo/client';
|
|
2
2
|
import { InMemoryCache } from '@apollo/client/cache';
|
|
3
3
|
import { ApolloClient } from '@apollo/client/core';
|
|
4
|
-
import { setContext } from '@apollo/client/link/context';
|
|
5
|
-
import { onError } from '@apollo/client/link/error';
|
|
6
|
-
import { RetryLink } from '@apollo/client/link/retry';
|
|
7
4
|
import { CachePersistor } from 'apollo-cache-persist';
|
|
8
|
-
import getWithPath from 'lodash.get';
|
|
9
|
-
import setWithPath from 'lodash.set';
|
|
10
5
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
11
6
|
|
|
12
|
-
import MutationQueueLink from '@adobe/apollo-link-mutation-queue';
|
|
13
7
|
import attachClient from '@magento/peregrine/lib/Apollo/attachClientToStore';
|
|
14
8
|
import { clearCartDataFromCache } from '@magento/peregrine/lib/Apollo/clearCartDataFromCache';
|
|
15
9
|
import { clearCustomerDataFromCache } from '@magento/peregrine/lib/Apollo/clearCustomerDataFromCache';
|
|
16
10
|
import { CACHE_PERSIST_PREFIX } from '@magento/peregrine/lib/Apollo/constants';
|
|
11
|
+
import getLinks from '@magento/peregrine/lib/Apollo/links';
|
|
17
12
|
import typePolicies from '@magento/peregrine/lib/Apollo/policies';
|
|
18
|
-
import MagentoGQLCacheLink from '@magento/peregrine/lib/Apollo/magentoGqlCacheLink';
|
|
19
13
|
import { BrowserPersistence } from '@magento/peregrine/lib/util';
|
|
20
|
-
|
|
14
|
+
|
|
15
|
+
const isServer = !globalThis.document;
|
|
16
|
+
const storage = new BrowserPersistence();
|
|
17
|
+
const urlHasStoreCode = process.env.USE_STORE_CODE_IN_URL === 'true';
|
|
21
18
|
|
|
22
19
|
export const useAdapter = props => {
|
|
23
|
-
const { origin, store, styles } = props;
|
|
20
|
+
const { apiUrl, configureLinks, origin, store, styles } = props;
|
|
24
21
|
const storeCode = storage.getItem('store_view_code') || STORE_VIEW_CODE;
|
|
25
22
|
const basename = urlHasStoreCode ? `/${storeCode}` : null;
|
|
26
23
|
const [initialized, setInitialized] = useState(false);
|
|
27
24
|
|
|
28
|
-
const apiBase = useMemo(
|
|
29
|
-
origin
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const authLink = useMemo(
|
|
33
|
-
() =>
|
|
34
|
-
setContext((_, { headers }) => {
|
|
35
|
-
// get the authentication token from local storage if it exists.
|
|
36
|
-
const token = storage.getItem('signin_token');
|
|
37
|
-
|
|
38
|
-
// return the headers to the context so httpLink can read them
|
|
39
|
-
return {
|
|
40
|
-
headers: {
|
|
41
|
-
...headers,
|
|
42
|
-
authorization: token ? `Bearer ${token}` : ''
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
}),
|
|
46
|
-
[]
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const errorLink = useMemo(
|
|
50
|
-
() =>
|
|
51
|
-
onError(handler => {
|
|
52
|
-
const { graphQLErrors, networkError, response } = handler;
|
|
53
|
-
|
|
54
|
-
if (graphQLErrors) {
|
|
55
|
-
graphQLErrors.forEach(({ message, locations, path }) =>
|
|
56
|
-
console.log(
|
|
57
|
-
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
|
58
|
-
)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (networkError) {
|
|
63
|
-
console.log(`[Network error]: ${networkError}`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (response) {
|
|
67
|
-
const { data, errors } = response;
|
|
68
|
-
let pathToCartItems;
|
|
69
|
-
|
|
70
|
-
// It's within the GraphQL spec to receive data and errors, where
|
|
71
|
-
// errors are merely informational and not intended to block. Almost
|
|
72
|
-
// all existing components were not built with this in mind, so we
|
|
73
|
-
// build special handling of this error message so we can deal with
|
|
74
|
-
// it at the time we deem appropriate.
|
|
75
|
-
errors.forEach(({ message, path }, index) => {
|
|
76
|
-
if (
|
|
77
|
-
message ===
|
|
78
|
-
'Some of the products are out of stock.' ||
|
|
79
|
-
message ===
|
|
80
|
-
'There are no source items with the in stock status' ||
|
|
81
|
-
message === 'The requested qty is not available'
|
|
82
|
-
) {
|
|
83
|
-
if (!pathToCartItems) {
|
|
84
|
-
pathToCartItems = path.slice(0, -1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Set the error to null to be cleaned up later
|
|
88
|
-
response.errors[index] = null;
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// indicator that we have some cleanup to perform on the response
|
|
93
|
-
if (pathToCartItems) {
|
|
94
|
-
const cartItems = getWithPath(data, pathToCartItems);
|
|
95
|
-
const filteredCartItems = cartItems.filter(
|
|
96
|
-
cartItem => cartItem !== null
|
|
97
|
-
);
|
|
98
|
-
setWithPath(data, pathToCartItems, filteredCartItems);
|
|
99
|
-
|
|
100
|
-
const filteredErrors = response.errors.filter(
|
|
101
|
-
error => error !== null
|
|
102
|
-
);
|
|
103
|
-
// If all errors were stock related and set to null, reset the error response so it doesn't throw
|
|
104
|
-
response.errors = filteredErrors.length
|
|
105
|
-
? filteredErrors
|
|
106
|
-
: undefined;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}),
|
|
110
|
-
[]
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
// Warning: `useGETForQueries` risks exceeding URL length limits.
|
|
114
|
-
// These limits in practice are typically set at or behind where TLS
|
|
115
|
-
// terminates. For Magento Cloud & Fastly, 8kb is the maximum by default.
|
|
116
|
-
// https://docs.fastly.com/en/guides/resource-limits#request-and-response-limits
|
|
117
|
-
const httpLink = useMemo(
|
|
118
|
-
() =>
|
|
119
|
-
createHttpLink({
|
|
120
|
-
fetch: customFetchToShrinkQuery,
|
|
121
|
-
useGETForQueries: true,
|
|
122
|
-
uri: apiBase
|
|
123
|
-
}),
|
|
124
|
-
[apiBase]
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const mutationQueueLink = useMemo(() => new MutationQueueLink(), []);
|
|
128
|
-
|
|
129
|
-
const retryLink = useMemo(
|
|
130
|
-
() =>
|
|
131
|
-
new RetryLink({
|
|
132
|
-
delay: {
|
|
133
|
-
initial: 300,
|
|
134
|
-
max: Infinity,
|
|
135
|
-
jitter: true
|
|
136
|
-
},
|
|
137
|
-
attempts: {
|
|
138
|
-
max: 5,
|
|
139
|
-
retryIf: error => error && !isServer && navigator.onLine
|
|
140
|
-
}
|
|
141
|
-
}),
|
|
142
|
-
[]
|
|
25
|
+
const apiBase = useMemo(
|
|
26
|
+
() => apiUrl || new URL('/graphql', origin).toString(),
|
|
27
|
+
[apiUrl, origin]
|
|
143
28
|
);
|
|
144
29
|
|
|
145
|
-
const
|
|
146
|
-
()
|
|
147
|
-
setContext((_, { headers }) => {
|
|
148
|
-
const storeCurrency =
|
|
149
|
-
storage.getItem('store_view_currency') || null;
|
|
150
|
-
const storeCode =
|
|
151
|
-
storage.getItem('store_view_code') || STORE_VIEW_CODE;
|
|
30
|
+
const apolloLink = useMemo(() => {
|
|
31
|
+
let links = getLinks(apiBase);
|
|
152
32
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
...headers,
|
|
157
|
-
store: storeCode,
|
|
158
|
-
...(storeCurrency && {
|
|
159
|
-
'Content-Currency': storeCurrency
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
}),
|
|
164
|
-
[]
|
|
165
|
-
);
|
|
33
|
+
if (configureLinks) {
|
|
34
|
+
links = configureLinks(links, apiBase);
|
|
35
|
+
}
|
|
166
36
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const apolloLink = useMemo(
|
|
170
|
-
() =>
|
|
171
|
-
ApolloLink.from([
|
|
172
|
-
// preserve this array order, it's important
|
|
173
|
-
// as the terminating link, `httpLink` must be last
|
|
174
|
-
mutationQueueLink,
|
|
175
|
-
retryLink,
|
|
176
|
-
authLink,
|
|
177
|
-
magentoGqlCacheLink,
|
|
178
|
-
storeLink,
|
|
179
|
-
errorLink,
|
|
180
|
-
httpLink
|
|
181
|
-
]),
|
|
182
|
-
[
|
|
183
|
-
authLink,
|
|
184
|
-
errorLink,
|
|
185
|
-
httpLink,
|
|
186
|
-
magentoGqlCacheLink,
|
|
187
|
-
mutationQueueLink,
|
|
188
|
-
retryLink,
|
|
189
|
-
storeLink
|
|
190
|
-
]
|
|
191
|
-
);
|
|
37
|
+
return ApolloLink.from(Array.from(links.values()));
|
|
38
|
+
}, [apiBase, configureLinks]);
|
|
192
39
|
|
|
193
40
|
const createApolloClient = useCallback((cache, link) => {
|
|
194
41
|
return new ApolloClient({
|
|
@@ -222,10 +69,10 @@ export const useAdapter = props => {
|
|
|
222
69
|
|
|
223
70
|
// Clear other stores
|
|
224
71
|
for (const store of AVAILABLE_STORE_VIEWS) {
|
|
225
|
-
if (store.
|
|
72
|
+
if (store.store_code !== storeCode) {
|
|
226
73
|
// Get saved data directly from local storage
|
|
227
74
|
const existingStorePersistor = globalThis.localStorage.getItem(
|
|
228
|
-
`${CACHE_PERSIST_PREFIX}-${store.
|
|
75
|
+
`${CACHE_PERSIST_PREFIX}-${store.store_code}`
|
|
229
76
|
);
|
|
230
77
|
|
|
231
78
|
// Make sure we have data available
|
|
@@ -245,7 +92,10 @@ export const useAdapter = props => {
|
|
|
245
92
|
|
|
246
93
|
storeClient.persistor = isServer
|
|
247
94
|
? null
|
|
248
|
-
: createCachePersistor(
|
|
95
|
+
: createCachePersistor(
|
|
96
|
+
store.store_code,
|
|
97
|
+
storeCache
|
|
98
|
+
);
|
|
249
99
|
|
|
250
100
|
// Clear other store
|
|
251
101
|
if (cacheType === 'cart') {
|
|
@@ -320,10 +170,6 @@ export const useAdapter = props => {
|
|
|
320
170
|
};
|
|
321
171
|
};
|
|
322
172
|
|
|
323
|
-
const isServer = !globalThis.document;
|
|
324
|
-
const storage = new BrowserPersistence();
|
|
325
|
-
const urlHasStoreCode = process.env.USE_STORE_CODE_IN_URL === 'true';
|
|
326
|
-
|
|
327
173
|
/**
|
|
328
174
|
* To improve initial load time, create an apollo cache object as soon as
|
|
329
175
|
* this module is executed, since it doesn't depend on any component props.
|
|
@@ -334,26 +180,3 @@ const preInstantiatedCache = new InMemoryCache({
|
|
|
334
180
|
possibleTypes: POSSIBLE_TYPES,
|
|
335
181
|
typePolicies
|
|
336
182
|
});
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Intercept and shrink URLs from GET queries.
|
|
340
|
-
*
|
|
341
|
-
* Using GET makes it possible to use edge caching in Magento Cloud, but risks
|
|
342
|
-
* exceeding URL limits with default usage of Apollo's http link.
|
|
343
|
-
*
|
|
344
|
-
* `shrinkQuery` encodes the URL in a more efficient way.
|
|
345
|
-
*
|
|
346
|
-
* @param {*} uri
|
|
347
|
-
* @param {*} options
|
|
348
|
-
*/
|
|
349
|
-
const customFetchToShrinkQuery = (uri, options) => {
|
|
350
|
-
// TODO: add `ismorphic-fetch` or equivalent to avoid this error
|
|
351
|
-
if (typeof globalThis.fetch !== 'function') {
|
|
352
|
-
console.error('This environment does not define `fetch`.');
|
|
353
|
-
return () => {};
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const resource = options.method === 'GET' ? shrinkQuery(uri) : uri;
|
|
357
|
-
|
|
358
|
-
return globalThis.fetch(resource, options);
|
|
359
|
-
};
|
|
@@ -20,6 +20,10 @@ const GET_PRODUCT_DETAIL = gql`
|
|
|
20
20
|
currency
|
|
21
21
|
value
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
discount {
|
|
25
|
+
amount_off
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
... on ConfigurableProduct {
|
|
@@ -50,6 +54,10 @@ const GET_PRODUCT_DETAIL = gql`
|
|
|
50
54
|
currency
|
|
51
55
|
value
|
|
52
56
|
}
|
|
57
|
+
|
|
58
|
+
discount {
|
|
59
|
+
amount_off
|
|
60
|
+
}
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
}
|
|
@@ -4,16 +4,20 @@ import { useMutation, useQuery } from '@apollo/client';
|
|
|
4
4
|
import mergeOperations from '../../util/shallowMerge';
|
|
5
5
|
import { useCartContext } from '../../context/cart';
|
|
6
6
|
import defaultOperations from './addToCartDialog.gql';
|
|
7
|
+
import { useEventingContext } from '../../context/eventing';
|
|
7
8
|
|
|
8
9
|
export const useAddToCartDialog = props => {
|
|
9
10
|
const { item, onClose } = props;
|
|
10
11
|
const sku = item && item.product.sku;
|
|
11
12
|
|
|
13
|
+
const [, { dispatch }] = useEventingContext();
|
|
14
|
+
|
|
12
15
|
const operations = mergeOperations(defaultOperations, props.operations);
|
|
13
16
|
|
|
14
17
|
const [userSelectedOptions, setUserSelectedOptions] = useState(new Map());
|
|
15
18
|
const [currentImage, setCurrentImage] = useState();
|
|
16
19
|
const [currentPrice, setCurrentPrice] = useState();
|
|
20
|
+
const [currentDiscount, setCurrentDiscount] = useState();
|
|
17
21
|
|
|
18
22
|
const [{ cartId }] = useCartContext();
|
|
19
23
|
|
|
@@ -89,6 +93,11 @@ export const useAddToCartDialog = props => {
|
|
|
89
93
|
? selectedVariant.price_range.maximum_price.final_price
|
|
90
94
|
: product.price_range.maximum_price.final_price;
|
|
91
95
|
|
|
96
|
+
const discount = selectedVariant
|
|
97
|
+
? selectedVariant.price_range.maximum_price.discount
|
|
98
|
+
: product.price_range.maximum_price.discount;
|
|
99
|
+
|
|
100
|
+
setCurrentDiscount(discount);
|
|
92
101
|
setCurrentPrice(finalPrice);
|
|
93
102
|
}
|
|
94
103
|
}, [data, selectedOptionsArray.length]);
|
|
@@ -108,22 +117,57 @@ export const useAddToCartDialog = props => {
|
|
|
108
117
|
|
|
109
118
|
const handleAddToCart = useCallback(async () => {
|
|
110
119
|
try {
|
|
120
|
+
const quantity = 1;
|
|
121
|
+
|
|
111
122
|
await addProductToCart({
|
|
112
123
|
variables: {
|
|
113
124
|
cartId,
|
|
114
125
|
cartItem: {
|
|
115
|
-
quantity
|
|
126
|
+
quantity,
|
|
116
127
|
selected_options: selectedOptionsArray,
|
|
117
128
|
sku
|
|
118
129
|
}
|
|
119
130
|
}
|
|
120
131
|
});
|
|
121
132
|
|
|
133
|
+
const selectedOptionsLabels =
|
|
134
|
+
selectedOptionsArray?.map((value, i) => ({
|
|
135
|
+
attribute: item.product.configurable_options[i].label,
|
|
136
|
+
value:
|
|
137
|
+
item.product.configurable_options[i].values.find(
|
|
138
|
+
x => x.uid === value
|
|
139
|
+
)?.label || null
|
|
140
|
+
})) || null;
|
|
141
|
+
|
|
142
|
+
dispatch({
|
|
143
|
+
type: 'CART_ADD_ITEM',
|
|
144
|
+
payload: {
|
|
145
|
+
cartId,
|
|
146
|
+
sku: item.product.sku,
|
|
147
|
+
name: item.product.name,
|
|
148
|
+
priceTotal: currentPrice.value,
|
|
149
|
+
currencyCode: currentPrice.currency,
|
|
150
|
+
discountAmount: currentDiscount.amount_off,
|
|
151
|
+
selectedOptions: selectedOptionsLabels,
|
|
152
|
+
quantity
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
122
156
|
handleOnClose();
|
|
123
157
|
} catch (error) {
|
|
124
158
|
console.error(error);
|
|
125
159
|
}
|
|
126
|
-
}, [
|
|
160
|
+
}, [
|
|
161
|
+
addProductToCart,
|
|
162
|
+
cartId,
|
|
163
|
+
currentDiscount,
|
|
164
|
+
currentPrice,
|
|
165
|
+
dispatch,
|
|
166
|
+
handleOnClose,
|
|
167
|
+
item,
|
|
168
|
+
selectedOptionsArray,
|
|
169
|
+
sku
|
|
170
|
+
]);
|
|
127
171
|
|
|
128
172
|
const imageProps = useMemo(() => {
|
|
129
173
|
if (currentImage) {
|
|
@@ -6,6 +6,7 @@ import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
|
6
6
|
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
7
7
|
|
|
8
8
|
import defaultOperations from './addressBookPage.gql';
|
|
9
|
+
import { useEventingContext } from '../../context/eventing';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* A talon to support the functionality of the Address Book page.
|
|
@@ -35,7 +36,9 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
35
36
|
actions: { setPageLoading }
|
|
36
37
|
}
|
|
37
38
|
] = useAppContext();
|
|
38
|
-
const [{ isSignedIn }] = useUserContext();
|
|
39
|
+
const [{ isSignedIn, currentUser }] = useUserContext();
|
|
40
|
+
|
|
41
|
+
const [, { dispatch }] = useEventingContext();
|
|
39
42
|
|
|
40
43
|
const { data: customerAddressesData, loading } = useQuery(
|
|
41
44
|
getCustomerAddressesQuery,
|
|
@@ -112,6 +115,14 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
112
115
|
awaitRefetchQueries: true
|
|
113
116
|
});
|
|
114
117
|
|
|
118
|
+
dispatch({
|
|
119
|
+
type: 'USER_ADDRESS_DELETE',
|
|
120
|
+
payload: {
|
|
121
|
+
addressId: confirmDeleteAddressId,
|
|
122
|
+
user: currentUser
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
115
126
|
setConfirmDeleteAddressId(null);
|
|
116
127
|
} catch {
|
|
117
128
|
return;
|
|
@@ -119,7 +130,9 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
119
130
|
}, [
|
|
120
131
|
confirmDeleteAddressId,
|
|
121
132
|
deleteCustomerAddress,
|
|
122
|
-
getCustomerAddressesQuery
|
|
133
|
+
getCustomerAddressesQuery,
|
|
134
|
+
dispatch,
|
|
135
|
+
currentUser
|
|
123
136
|
]);
|
|
124
137
|
|
|
125
138
|
const handleEditAddress = useCallback(address => {
|
|
@@ -139,21 +152,32 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
139
152
|
async formValues => {
|
|
140
153
|
if (isDialogEditMode) {
|
|
141
154
|
try {
|
|
155
|
+
const address = {
|
|
156
|
+
...formValues,
|
|
157
|
+
// Sends value as empty if none are provided
|
|
158
|
+
middlename: formValues.middlename || '',
|
|
159
|
+
// Cleans up the street array when values are null or undefined
|
|
160
|
+
street: formValues.street.filter(e => e)
|
|
161
|
+
};
|
|
162
|
+
|
|
142
163
|
await updateCustomerAddress({
|
|
143
164
|
variables: {
|
|
144
165
|
addressId: formAddress.id,
|
|
145
|
-
updated_address:
|
|
146
|
-
...formValues,
|
|
147
|
-
// Sends value as empty if none are provided
|
|
148
|
-
middlename: formValues.middlename || '',
|
|
149
|
-
// Cleans up the street array when values are null or undefined
|
|
150
|
-
street: formValues.street.filter(e => e)
|
|
151
|
-
}
|
|
166
|
+
updated_address: address
|
|
152
167
|
},
|
|
153
168
|
refetchQueries: [{ query: getCustomerAddressesQuery }],
|
|
154
169
|
awaitRefetchQueries: true
|
|
155
170
|
});
|
|
156
171
|
|
|
172
|
+
dispatch({
|
|
173
|
+
type: 'USER_ADDRESS_EDIT',
|
|
174
|
+
payload: {
|
|
175
|
+
id: formAddress.id,
|
|
176
|
+
address: address,
|
|
177
|
+
user: currentUser
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
157
181
|
setIsDialogOpen(false);
|
|
158
182
|
} catch {
|
|
159
183
|
// Make sure any errors from the mutations are displayed.
|
|
@@ -166,20 +190,29 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
166
190
|
}
|
|
167
191
|
} else {
|
|
168
192
|
try {
|
|
193
|
+
const address = {
|
|
194
|
+
...formValues,
|
|
195
|
+
// Sends value as empty if none are provided
|
|
196
|
+
middlename: formValues.middlename || '',
|
|
197
|
+
// Cleans up the street array when values are null or undefined
|
|
198
|
+
street: formValues.street.filter(e => e)
|
|
199
|
+
};
|
|
169
200
|
await createCustomerAddress({
|
|
170
201
|
variables: {
|
|
171
|
-
address
|
|
172
|
-
...formValues,
|
|
173
|
-
// Sends value as empty if none are provided
|
|
174
|
-
middlename: formValues.middlename || '',
|
|
175
|
-
// Cleans up the street array when values are null or undefined
|
|
176
|
-
street: formValues.street.filter(e => e)
|
|
177
|
-
}
|
|
202
|
+
address
|
|
178
203
|
},
|
|
179
204
|
refetchQueries: [{ query: getCustomerAddressesQuery }],
|
|
180
205
|
awaitRefetchQueries: true
|
|
181
206
|
});
|
|
182
207
|
|
|
208
|
+
dispatch({
|
|
209
|
+
type: 'USER_ADDRESS_CREATE',
|
|
210
|
+
payload: {
|
|
211
|
+
address,
|
|
212
|
+
user: currentUser
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
183
216
|
setIsDialogOpen(false);
|
|
184
217
|
} catch {
|
|
185
218
|
// Make sure any errors from the mutations are displayed.
|
|
@@ -197,7 +230,9 @@ export const useAddressBookPage = (props = {}) => {
|
|
|
197
230
|
formAddress,
|
|
198
231
|
getCustomerAddressesQuery,
|
|
199
232
|
isDialogEditMode,
|
|
200
|
-
updateCustomerAddress
|
|
233
|
+
updateCustomerAddress,
|
|
234
|
+
dispatch,
|
|
235
|
+
currentUser
|
|
201
236
|
]
|
|
202
237
|
);
|
|
203
238
|
|
|
@@ -5,6 +5,7 @@ import { useMutation } from '@apollo/client';
|
|
|
5
5
|
import mergeOperations from '../../util/shallowMerge';
|
|
6
6
|
import { useUserContext } from '../../context/user';
|
|
7
7
|
import DEFAULT_OPERATIONS from './authModal.gql';
|
|
8
|
+
import { useEventingContext } from '../../context/eventing';
|
|
8
9
|
|
|
9
10
|
const UNAUTHED_ONLY = ['CREATE_ACCOUNT', 'FORGOT_PASSWORD', 'SIGN_IN'];
|
|
10
11
|
|
|
@@ -52,6 +53,8 @@ export const useAuthModal = props => {
|
|
|
52
53
|
const [revokeToken] = useMutation(signOutMutation);
|
|
53
54
|
const history = useHistory();
|
|
54
55
|
|
|
56
|
+
const [, { dispatch }] = useEventingContext();
|
|
57
|
+
|
|
55
58
|
// If the user is authed, the only valid view is "MY_ACCOUNT".
|
|
56
59
|
// view an also be `MENU` but in that case we don't want to act.
|
|
57
60
|
useEffect(() => {
|
|
@@ -84,6 +87,11 @@ export const useAuthModal = props => {
|
|
|
84
87
|
const handleSignOut = useCallback(async () => {
|
|
85
88
|
setIsSigningOut(true);
|
|
86
89
|
|
|
90
|
+
dispatch({
|
|
91
|
+
type: 'USER_SIGN_OUT',
|
|
92
|
+
payload: currentUser
|
|
93
|
+
});
|
|
94
|
+
|
|
87
95
|
// Delete cart/user data from the redux store.
|
|
88
96
|
await signOut({ revokeToken });
|
|
89
97
|
|
|
@@ -91,7 +99,7 @@ export const useAuthModal = props => {
|
|
|
91
99
|
// would be to call apolloClient.resetStore() but that would require
|
|
92
100
|
// a large refactor.
|
|
93
101
|
history.go(0);
|
|
94
|
-
}, [history, revokeToken, signOut]);
|
|
102
|
+
}, [history, revokeToken, signOut, dispatch, currentUser]);
|
|
95
103
|
|
|
96
104
|
return {
|
|
97
105
|
handleCancel,
|
|
@@ -102,6 +110,8 @@ export const useAuthModal = props => {
|
|
|
102
110
|
showCreateAccount,
|
|
103
111
|
showForgotPassword,
|
|
104
112
|
showMyAccount,
|
|
105
|
-
username
|
|
113
|
+
username,
|
|
114
|
+
dispatch,
|
|
115
|
+
currentUser
|
|
106
116
|
};
|
|
107
117
|
};
|
|
@@ -57,7 +57,7 @@ export const useBreadcrumbs = props => {
|
|
|
57
57
|
|
|
58
58
|
// When we have breadcrumb data sort and normalize it for easy rendering.
|
|
59
59
|
const normalizedData = useMemo(() => {
|
|
60
|
-
if (!loading && data) {
|
|
60
|
+
if (!loading && data && data.categories.items.length) {
|
|
61
61
|
const breadcrumbData = data.categories.items[0].breadcrumbs;
|
|
62
62
|
|
|
63
63
|
return (
|
|
@@ -79,9 +79,14 @@ export const useBreadcrumbs = props => {
|
|
|
79
79
|
const { setShimmerType } = useInternalLink('category');
|
|
80
80
|
|
|
81
81
|
return {
|
|
82
|
-
currentCategory:
|
|
82
|
+
currentCategory:
|
|
83
|
+
(data &&
|
|
84
|
+
data.categories.items.length &&
|
|
85
|
+
data.categories.items[0].name) ||
|
|
86
|
+
'',
|
|
83
87
|
currentCategoryPath:
|
|
84
88
|
(data &&
|
|
89
|
+
data.categories.items.length &&
|
|
85
90
|
`${data.categories.items[0].url_path}${categoryUrlSuffix ||
|
|
86
91
|
''}`) ||
|
|
87
92
|
'#',
|
|
@@ -6,11 +6,33 @@ export const configurableItemResponse = {
|
|
|
6
6
|
configurable_options: [
|
|
7
7
|
{
|
|
8
8
|
attribute_id: '123',
|
|
9
|
-
attribute_code: 'color'
|
|
9
|
+
attribute_code: 'color',
|
|
10
|
+
label: 'Color',
|
|
11
|
+
values: [
|
|
12
|
+
{
|
|
13
|
+
label: 'Lilac',
|
|
14
|
+
value_index: 1
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
label: 'Red',
|
|
18
|
+
value_index: 2
|
|
19
|
+
}
|
|
20
|
+
]
|
|
10
21
|
},
|
|
11
22
|
{
|
|
12
23
|
attribute_id: '456',
|
|
13
|
-
attribute_code: 'size'
|
|
24
|
+
attribute_code: 'size',
|
|
25
|
+
label: 'Red',
|
|
26
|
+
values: [
|
|
27
|
+
{
|
|
28
|
+
label: 'XS',
|
|
29
|
+
value_index: 1
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: 'S',
|
|
33
|
+
value_index: 2
|
|
34
|
+
}
|
|
35
|
+
]
|
|
14
36
|
}
|
|
15
37
|
],
|
|
16
38
|
variants: [
|
|
@@ -80,11 +102,24 @@ export const configurableItemResponse = {
|
|
|
80
102
|
};
|
|
81
103
|
|
|
82
104
|
export const cartItem = {
|
|
83
|
-
configurable_options: [
|
|
105
|
+
configurable_options: [
|
|
106
|
+
{ id: 123, value_id: 1, option_label: 'Color', value_label: 'Pink' },
|
|
107
|
+
{ id: 456, value_id: 1, option_label: 'Size', value_label: 'XS' }
|
|
108
|
+
],
|
|
84
109
|
id: 123,
|
|
85
110
|
uid: 'NDA=',
|
|
86
111
|
product: {
|
|
87
|
-
sku: 'SP01'
|
|
112
|
+
sku: 'SP01',
|
|
113
|
+
name: 'Product Name'
|
|
114
|
+
},
|
|
115
|
+
prices: {
|
|
116
|
+
price: {
|
|
117
|
+
value: 9.99,
|
|
118
|
+
currency: 'USD'
|
|
119
|
+
},
|
|
120
|
+
total_item_discount: {
|
|
121
|
+
value: 5
|
|
122
|
+
}
|
|
88
123
|
},
|
|
89
124
|
quantity: 5
|
|
90
125
|
};
|