@magento/peregrine 15.5.2 → 15.6.2-alpha12
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/context/cart.js +1 -43
- package/lib/hooks/useCustomerWishlistSkus/customerWishlist.gql.ce.js +1 -1
- package/lib/hooks/useCustomerWishlistSkus/useCustomerWishlistSkus.js +2 -16
- package/lib/store/middleware/auth.js +2 -2
- package/lib/talons/AddToCartDialog/useAddToCartDialog.js +57 -6
- package/lib/talons/App/useApp.js +3 -0
- package/lib/talons/CartPage/ProductListing/EditModal/useProductForm.js +15 -3
- package/lib/talons/FilterSidebar/useFilterSidebar.js +16 -4
- package/lib/talons/Gallery/useAddToCartButton.js +61 -7
- package/lib/talons/Gallery/useGallery.js +0 -4
- package/lib/talons/MagentoRoute/useMagentoRoute.js +1 -1
- package/lib/talons/ProductFullDetail/useProductFullDetail.js +50 -5
- package/lib/talons/SignIn/useSignIn.js +35 -7
- package/lib/talons/WishlistPage/useWishlist.js +76 -18
- package/lib/talons/WishlistPage/useWishlistItem.js +66 -11
- package/lib/talons/WishlistPage/wishlist.gql.js +2 -2
- package/lib/util/getOutOfStockVariants.js +21 -17
- package/lib/util/getOutOfStockVariantsWithInitialSelection.js +83 -31
- package/package.json +1 -1
package/lib/context/cart.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
createContext,
|
|
3
|
-
useContext,
|
|
4
|
-
useEffect,
|
|
5
|
-
useMemo,
|
|
6
|
-
useCallback
|
|
7
|
-
} from 'react';
|
|
1
|
+
import React, { createContext, useContext, useMemo, useCallback } from 'react';
|
|
8
2
|
import { connect } from 'react-redux';
|
|
9
|
-
import { useMutation } from '@apollo/client';
|
|
10
|
-
import gql from 'graphql-tag';
|
|
11
|
-
|
|
12
|
-
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
|
|
13
3
|
import actions from '../store/actions/cart/actions';
|
|
14
4
|
import * as asyncActions from '../store/actions/cart/asyncActions';
|
|
15
5
|
import bindActionCreators from '../util/bindActionCreators';
|
|
@@ -62,9 +52,6 @@ const CartContextProvider = props => {
|
|
|
62
52
|
return [derivedCartState, cartApi];
|
|
63
53
|
}, [cartApi, cartState, derivedDetails]);
|
|
64
54
|
|
|
65
|
-
const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
|
|
66
|
-
const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
|
|
67
|
-
|
|
68
55
|
// Storage listener to force a state update if cartId changes from another browser tab.
|
|
69
56
|
const storageListener = useCallback(() => {
|
|
70
57
|
const storage = new BrowserPersistence();
|
|
@@ -77,14 +64,6 @@ const CartContextProvider = props => {
|
|
|
77
64
|
|
|
78
65
|
useEventListener(globalThis, 'storage', storageListener);
|
|
79
66
|
|
|
80
|
-
useEffect(() => {
|
|
81
|
-
// cartApi.getCartDetails initializes the cart if there isn't one.
|
|
82
|
-
cartApi.getCartDetails({
|
|
83
|
-
fetchCartId,
|
|
84
|
-
fetchCartDetails
|
|
85
|
-
});
|
|
86
|
-
}, [cartApi, fetchCartDetails, fetchCartId]);
|
|
87
|
-
|
|
88
67
|
return (
|
|
89
68
|
<CartContext.Provider value={contextValue}>
|
|
90
69
|
{children}
|
|
@@ -105,24 +84,3 @@ export default connect(
|
|
|
105
84
|
)(CartContextProvider);
|
|
106
85
|
|
|
107
86
|
export const useCartContext = () => useContext(CartContext);
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* We normally do not keep GQL queries in Peregrine. All components should pass
|
|
111
|
-
* queries to talons/hooks. This is an exception to the rule because it would
|
|
112
|
-
* be unecessarily complex to pass these queries to the context provider.
|
|
113
|
-
*/
|
|
114
|
-
const CREATE_CART_MUTATION = gql`
|
|
115
|
-
mutation createCart {
|
|
116
|
-
cartId: createEmptyCart
|
|
117
|
-
}
|
|
118
|
-
`;
|
|
119
|
-
|
|
120
|
-
const CART_DETAILS_QUERY = gql`
|
|
121
|
-
query checkUserIsAuthed($cartId: String!) {
|
|
122
|
-
cart(cart_id: $cartId) {
|
|
123
|
-
# The purpose of this query is to check that the user is authorized
|
|
124
|
-
# to query on the current cart. Just fetch "id" to keep it small.
|
|
125
|
-
id
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
`;
|
|
@@ -7,7 +7,7 @@ export const GET_WISHLIST_ITEMS = gql`
|
|
|
7
7
|
customer {
|
|
8
8
|
wishlists {
|
|
9
9
|
id
|
|
10
|
-
items_v2(currentPage: $currentPage, pageSize:
|
|
10
|
+
items_v2(currentPage: $currentPage, pageSize: 20) {
|
|
11
11
|
items {
|
|
12
12
|
id
|
|
13
13
|
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
1
|
import { useQuery } from '@apollo/client';
|
|
3
2
|
import { useUserContext } from '../../context/user';
|
|
4
3
|
import mergeOperations from '../../util/shallowMerge';
|
|
@@ -16,19 +15,16 @@ export const useCustomerWishlistSkus = (props = {}) => {
|
|
|
16
15
|
const operations = mergeOperations(defaultOperations, props.operations);
|
|
17
16
|
const [{ isSignedIn }] = useUserContext();
|
|
18
17
|
|
|
19
|
-
const [currentPage, setCurrentPage] = useState(1);
|
|
20
|
-
|
|
21
18
|
const {
|
|
22
19
|
client,
|
|
23
20
|
data: { customerWishlistProducts }
|
|
24
21
|
} = useQuery(operations.getProductsInWishlistsQuery);
|
|
25
22
|
|
|
26
23
|
useQuery(operations.getWishlistItemsQuery, {
|
|
27
|
-
fetchPolicy: 'cache-
|
|
24
|
+
fetchPolicy: 'cache-first',
|
|
28
25
|
onCompleted: data => {
|
|
29
26
|
const itemsToAdd = new Set();
|
|
30
27
|
const wishlists = data.customer.wishlists;
|
|
31
|
-
let shouldFetchMore = false;
|
|
32
28
|
wishlists.map(wishlist => {
|
|
33
29
|
const items = wishlist.items_v2.items;
|
|
34
30
|
items.map(item => {
|
|
@@ -37,12 +33,6 @@ export const useCustomerWishlistSkus = (props = {}) => {
|
|
|
37
33
|
itemsToAdd.add(sku);
|
|
38
34
|
}
|
|
39
35
|
});
|
|
40
|
-
|
|
41
|
-
const pageInfo = wishlist.items_v2.page_info;
|
|
42
|
-
|
|
43
|
-
if (pageInfo.total_pages > pageInfo.current_page) {
|
|
44
|
-
shouldFetchMore = true;
|
|
45
|
-
}
|
|
46
36
|
});
|
|
47
37
|
|
|
48
38
|
if (itemsToAdd.size) {
|
|
@@ -56,14 +46,10 @@ export const useCustomerWishlistSkus = (props = {}) => {
|
|
|
56
46
|
}
|
|
57
47
|
});
|
|
58
48
|
}
|
|
59
|
-
|
|
60
|
-
if (shouldFetchMore) {
|
|
61
|
-
setCurrentPage(current => ++current);
|
|
62
|
-
}
|
|
63
49
|
},
|
|
64
50
|
skip: !isSignedIn,
|
|
65
51
|
variables: {
|
|
66
|
-
currentPage
|
|
52
|
+
currentPage: 1
|
|
67
53
|
}
|
|
68
54
|
});
|
|
69
55
|
};
|
|
@@ -64,11 +64,11 @@ const scheduleSignOut = store => next => action => {
|
|
|
64
64
|
intervals.set(parsedValue, intervalId);
|
|
65
65
|
}
|
|
66
66
|
} else if (isSigningOut(action.type)) {
|
|
67
|
-
for (const timeoutId of timeouts) {
|
|
67
|
+
for (const [, timeoutId] of timeouts) {
|
|
68
68
|
clearTimeout(timeoutId);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
for (const intervalId of intervals) {
|
|
71
|
+
for (const [, intervalId] of intervals) {
|
|
72
72
|
clearInterval(intervalId);
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { useMutation, useQuery } from '@apollo/client';
|
|
2
|
+
import { useMutation, useQuery, gql } from '@apollo/client';
|
|
3
3
|
|
|
4
4
|
import mergeOperations from '../../util/shallowMerge';
|
|
5
5
|
import { useCartContext } from '../../context/cart';
|
|
@@ -7,6 +7,8 @@ import defaultOperations from './addToCartDialog.gql';
|
|
|
7
7
|
import { useEventingContext } from '../../context/eventing';
|
|
8
8
|
import { isProductConfigurable } from '@magento/peregrine/lib/util/isProductConfigurable';
|
|
9
9
|
import { getOutOfStockVariants } from '@magento/peregrine/lib/util/getOutOfStockVariants';
|
|
10
|
+
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
|
|
11
|
+
import BrowserPersistence from '../../util/simplePersistence';
|
|
10
12
|
|
|
11
13
|
export const useAddToCartDialog = props => {
|
|
12
14
|
const { item, onClose } = props;
|
|
@@ -25,7 +27,51 @@ export const useAddToCartDialog = props => {
|
|
|
25
27
|
new Map()
|
|
26
28
|
);
|
|
27
29
|
|
|
28
|
-
const [{ cartId }] = useCartContext();
|
|
30
|
+
//const [{ cartId }] = useCartContext();
|
|
31
|
+
|
|
32
|
+
const [cartState, cartApi] = useCartContext();
|
|
33
|
+
|
|
34
|
+
const { cartId } = cartState;
|
|
35
|
+
|
|
36
|
+
// cart creation logic
|
|
37
|
+
|
|
38
|
+
const CREATE_CART_MUTATION = gql`
|
|
39
|
+
mutation createCart {
|
|
40
|
+
cartId: createEmptyCart
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const CART_DETAILS_QUERY = gql`
|
|
45
|
+
query checkUserIsAuthed($cartId: String!) {
|
|
46
|
+
cart(cart_id: $cartId) {
|
|
47
|
+
id
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
|
|
53
|
+
|
|
54
|
+
const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
|
|
55
|
+
|
|
56
|
+
const ensureCartId = useCallback(async () => {
|
|
57
|
+
let newCartId = cartId;
|
|
58
|
+
|
|
59
|
+
if (!newCartId) {
|
|
60
|
+
await cartApi.getCartDetails({
|
|
61
|
+
fetchCartId,
|
|
62
|
+
|
|
63
|
+
fetchCartDetails
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
newCartId = new BrowserPersistence().getItem('cartId');
|
|
67
|
+
|
|
68
|
+
if (!newCartId) {
|
|
69
|
+
throw new Error('Failed to create a new cart');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return newCartId;
|
|
74
|
+
}, [cartId, cartApi, fetchCartId, fetchCartDetails]);
|
|
29
75
|
|
|
30
76
|
const optionCodes = useMemo(() => {
|
|
31
77
|
const optionCodeMap = new Map();
|
|
@@ -112,7 +158,9 @@ export const useAddToCartDialog = props => {
|
|
|
112
158
|
fetchPolicy: 'cache-and-network',
|
|
113
159
|
nextFetchPolicy: 'cache-first',
|
|
114
160
|
variables: {
|
|
115
|
-
configurableOptionValues: selectedOptionsArray
|
|
161
|
+
configurableOptionValues: selectedOptionsArray.length
|
|
162
|
+
? selectedOptionsArray
|
|
163
|
+
: null,
|
|
116
164
|
sku
|
|
117
165
|
},
|
|
118
166
|
skip: !sku
|
|
@@ -127,6 +175,7 @@ export const useAddToCartDialog = props => {
|
|
|
127
175
|
useEffect(() => {
|
|
128
176
|
if (data) {
|
|
129
177
|
const product = data.products.items[0];
|
|
178
|
+
console.log('useAddToCartDialog.js - data', data);
|
|
130
179
|
const {
|
|
131
180
|
media_gallery: selectedProductMediaGallery,
|
|
132
181
|
variant: selectedVariant
|
|
@@ -181,12 +230,14 @@ export const useAddToCartDialog = props => {
|
|
|
181
230
|
);
|
|
182
231
|
|
|
183
232
|
const handleAddToCart = useCallback(async () => {
|
|
233
|
+
//console.log("useAddToCartDialog.js handleAddToCart is called for ",cartId);
|
|
184
234
|
try {
|
|
235
|
+
const ensuredCartId = await ensureCartId();
|
|
185
236
|
const quantity = 1;
|
|
186
237
|
|
|
187
238
|
await addProductToCart({
|
|
188
239
|
variables: {
|
|
189
|
-
cartId,
|
|
240
|
+
cartId: ensuredCartId,
|
|
190
241
|
cartItem: {
|
|
191
242
|
quantity,
|
|
192
243
|
selected_options: selectedOptionsArray,
|
|
@@ -207,7 +258,7 @@ export const useAddToCartDialog = props => {
|
|
|
207
258
|
dispatch({
|
|
208
259
|
type: 'CART_ADD_ITEM',
|
|
209
260
|
payload: {
|
|
210
|
-
cartId,
|
|
261
|
+
cartId: ensuredCartId,
|
|
211
262
|
sku: item.product.sku,
|
|
212
263
|
name: item.product.name,
|
|
213
264
|
pricing: item.product.price,
|
|
@@ -225,7 +276,7 @@ export const useAddToCartDialog = props => {
|
|
|
225
276
|
}
|
|
226
277
|
}, [
|
|
227
278
|
addProductToCart,
|
|
228
|
-
|
|
279
|
+
ensureCartId,
|
|
229
280
|
currentDiscount,
|
|
230
281
|
currentPrice,
|
|
231
282
|
dispatch,
|
package/lib/talons/App/useApp.js
CHANGED
|
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useMemo } from 'react';
|
|
|
2
2
|
import { useHistory } from 'react-router-dom';
|
|
3
3
|
|
|
4
4
|
import errorRecord from '@magento/peregrine/lib/util/createErrorRecord';
|
|
5
|
+
import { useCustomerWishlistSkus } from '@magento/peregrine/lib/hooks/useCustomerWishlistSkus/useCustomerWishlistSkus';
|
|
5
6
|
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
6
7
|
|
|
7
8
|
const dismissers = new WeakMap();
|
|
@@ -41,6 +42,8 @@ export const useApp = props => {
|
|
|
41
42
|
} = props;
|
|
42
43
|
const history = useHistory();
|
|
43
44
|
|
|
45
|
+
useCustomerWishlistSkus();
|
|
46
|
+
|
|
44
47
|
const reload = useCallback(() => {
|
|
45
48
|
if (process.env.NODE_ENV !== 'development') {
|
|
46
49
|
history.go(0);
|
|
@@ -202,19 +202,31 @@ export const useProductForm = props => {
|
|
|
202
202
|
|
|
203
203
|
const outOfStockVariants = useMemo(() => {
|
|
204
204
|
if (cartItem && configItem) {
|
|
205
|
-
const product =
|
|
205
|
+
const product = configItem;
|
|
206
|
+
const currentSelections = new Map();
|
|
207
|
+
|
|
208
|
+
cartItem.configurable_options.forEach(option => {
|
|
209
|
+
currentSelections.set(String(option.id), option.value_id);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
optionSelections.forEach((value, key) => {
|
|
213
|
+
currentSelections.set(key, value);
|
|
214
|
+
});
|
|
215
|
+
|
|
206
216
|
return getOutOfStockVariantsWithInitialSelection(
|
|
207
217
|
product,
|
|
208
218
|
configurableOptionCodes,
|
|
209
|
-
|
|
219
|
+
currentSelections,
|
|
210
220
|
configItem,
|
|
211
221
|
isOutOfStockProductDisplayed
|
|
212
222
|
);
|
|
213
223
|
}
|
|
224
|
+
|
|
225
|
+
return [];
|
|
214
226
|
}, [
|
|
215
227
|
cartItem,
|
|
216
228
|
configurableOptionCodes,
|
|
217
|
-
|
|
229
|
+
optionSelections,
|
|
218
230
|
configItem,
|
|
219
231
|
isOutOfStockProductDisplayed
|
|
220
232
|
]);
|
|
@@ -182,10 +182,22 @@ export const useFilterSidebar = props => {
|
|
|
182
182
|
}, [handleClose]);
|
|
183
183
|
|
|
184
184
|
const handleReset = useCallback(() => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
filterApi.clear();
|
|
186
|
+
|
|
187
|
+
const params = new URLSearchParams(search);
|
|
188
|
+
const filterKeys = [];
|
|
189
|
+
for (const key of params.keys()) {
|
|
190
|
+
if (key.endsWith('[filter]')) {
|
|
191
|
+
filterKeys.push(key);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
for (const key of filterKeys) {
|
|
195
|
+
params.delete(key);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const newSearch = `?${params.toString()}`;
|
|
199
|
+
history.replace({ pathname, search: newSearch });
|
|
200
|
+
}, [filterApi, search, history, pathname]);
|
|
189
201
|
|
|
190
202
|
const handleKeyDownActions = useCallback(
|
|
191
203
|
event => {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { useMutation } from '@apollo/client';
|
|
2
|
+
import { useMutation, gql } from '@apollo/client';
|
|
3
3
|
import { useHistory } from 'react-router-dom';
|
|
4
4
|
|
|
5
5
|
import { useCartContext } from '../../context/cart';
|
|
6
6
|
import { useEventingContext } from '../../context/eventing';
|
|
7
7
|
import resourceUrl from '../../util/makeUrl';
|
|
8
8
|
import operations from './addToCart.gql';
|
|
9
|
+
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
|
|
10
|
+
import BrowserPersistence from '../../util/simplePersistence';
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* @param {String} props.item.uid - uid of item
|
|
@@ -29,6 +31,20 @@ const UNSUPPORTED_PRODUCT_TYPES = [
|
|
|
29
31
|
'DownloadableProduct'
|
|
30
32
|
];
|
|
31
33
|
|
|
34
|
+
const CREATE_CART_MUTATION = gql`
|
|
35
|
+
mutation createCart {
|
|
36
|
+
cartId: createEmptyCart
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
|
|
40
|
+
const CART_DETAILS_QUERY = gql`
|
|
41
|
+
query checkUserIsAuthed($cartId: String!) {
|
|
42
|
+
cart(cart_id: $cartId) {
|
|
43
|
+
id
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
|
|
32
48
|
export const useAddToCartButton = props => {
|
|
33
49
|
const { item, urlSuffix } = props;
|
|
34
50
|
|
|
@@ -36,6 +52,12 @@ export const useAddToCartButton = props => {
|
|
|
36
52
|
|
|
37
53
|
const [isLoading, setIsLoading] = useState(false);
|
|
38
54
|
|
|
55
|
+
const [cartState, cartApi] = useCartContext();
|
|
56
|
+
const { cartId } = cartState;
|
|
57
|
+
|
|
58
|
+
const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
|
|
59
|
+
const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
|
|
60
|
+
|
|
39
61
|
const isInStock = item.stock_status === 'IN_STOCK';
|
|
40
62
|
|
|
41
63
|
const productType = item
|
|
@@ -52,21 +74,42 @@ export const useAddToCartButton = props => {
|
|
|
52
74
|
|
|
53
75
|
const history = useHistory();
|
|
54
76
|
|
|
55
|
-
const [{ cartId }] = useCartContext();
|
|
56
|
-
|
|
57
77
|
const [addToCart] = useMutation(operations.ADD_ITEM);
|
|
58
78
|
|
|
79
|
+
// helper: ensure we have a valid cartId before adding
|
|
80
|
+
const ensureCartId = useCallback(async () => {
|
|
81
|
+
let newCartId = cartId;
|
|
82
|
+
if (!newCartId) {
|
|
83
|
+
console.log('No cart ID found, creating a new cart...');
|
|
84
|
+
await cartApi.getCartDetails({
|
|
85
|
+
fetchCartId,
|
|
86
|
+
fetchCartDetails
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
newCartId = new BrowserPersistence().getItem('cartId');
|
|
90
|
+
|
|
91
|
+
if (!newCartId) {
|
|
92
|
+
throw new Error('Failed to create a new cart');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return newCartId;
|
|
96
|
+
}, [cartId, cartApi, fetchCartId, fetchCartDetails]);
|
|
97
|
+
|
|
59
98
|
const handleAddToCart = useCallback(async () => {
|
|
60
99
|
try {
|
|
61
100
|
if (productType === 'SimpleProduct' || productType === 'simple') {
|
|
62
101
|
setIsLoading(true);
|
|
63
102
|
|
|
64
103
|
const quantity = 1;
|
|
104
|
+
let newCartId;
|
|
65
105
|
|
|
66
106
|
if (item.uid) {
|
|
107
|
+
// ensure cart right before addToCart
|
|
108
|
+
newCartId = await ensureCartId();
|
|
109
|
+
|
|
67
110
|
await addToCart({
|
|
68
111
|
variables: {
|
|
69
|
-
cartId,
|
|
112
|
+
cartId: newCartId,
|
|
70
113
|
cartItem: {
|
|
71
114
|
quantity,
|
|
72
115
|
entered_options: [
|
|
@@ -80,9 +123,12 @@ export const useAddToCartButton = props => {
|
|
|
80
123
|
}
|
|
81
124
|
});
|
|
82
125
|
} else {
|
|
126
|
+
// ensure cart right before addToCart
|
|
127
|
+
newCartId = await ensureCartId();
|
|
128
|
+
|
|
83
129
|
await addToCart({
|
|
84
130
|
variables: {
|
|
85
|
-
cartId,
|
|
131
|
+
cartId: newCartId,
|
|
86
132
|
cartItem: {
|
|
87
133
|
quantity,
|
|
88
134
|
sku: item.sku
|
|
@@ -94,7 +140,7 @@ export const useAddToCartButton = props => {
|
|
|
94
140
|
dispatch({
|
|
95
141
|
type: 'CART_ADD_ITEM',
|
|
96
142
|
payload: {
|
|
97
|
-
cartId,
|
|
143
|
+
cartId: newCartId,
|
|
98
144
|
sku: item.sku,
|
|
99
145
|
name: item.name,
|
|
100
146
|
pricing: {
|
|
@@ -130,7 +176,15 @@ export const useAddToCartButton = props => {
|
|
|
130
176
|
} catch (error) {
|
|
131
177
|
console.error(error);
|
|
132
178
|
}
|
|
133
|
-
}, [
|
|
179
|
+
}, [
|
|
180
|
+
productType,
|
|
181
|
+
addToCart,
|
|
182
|
+
item,
|
|
183
|
+
dispatch,
|
|
184
|
+
history,
|
|
185
|
+
urlSuffix,
|
|
186
|
+
ensureCartId
|
|
187
|
+
]);
|
|
134
188
|
|
|
135
189
|
return {
|
|
136
190
|
handleAddToCart,
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { useQuery } from '@apollo/client';
|
|
2
2
|
|
|
3
|
-
import { useCustomerWishlistSkus } from '../../hooks/useCustomerWishlistSkus/useCustomerWishlistSkus';
|
|
4
|
-
|
|
5
3
|
import mergeOperations from '../../util/shallowMerge';
|
|
6
4
|
import defaultOperations from './gallery.gql';
|
|
7
5
|
|
|
8
6
|
export const useGallery = (props = {}) => {
|
|
9
7
|
const operations = mergeOperations(defaultOperations, props.operations);
|
|
10
8
|
|
|
11
|
-
useCustomerWishlistSkus();
|
|
12
|
-
|
|
13
9
|
const { data: storeConfigData } = useQuery(operations.getStoreConfigQuery, {
|
|
14
10
|
fetchPolicy: 'cache-and-network'
|
|
15
11
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useState, useMemo } from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
|
-
import { useMutation, useQuery } from '@apollo/client';
|
|
3
|
+
import { useMutation, useQuery, gql } from '@apollo/client';
|
|
4
4
|
import { useCartContext } from '@magento/peregrine/lib/context/cart';
|
|
5
5
|
import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
6
6
|
|
|
@@ -13,6 +13,8 @@ import mergeOperations from '../../util/shallowMerge';
|
|
|
13
13
|
import defaultOperations from './productFullDetail.gql';
|
|
14
14
|
import { useEventingContext } from '../../context/eventing';
|
|
15
15
|
import { getOutOfStockVariants } from '@magento/peregrine/lib/util/getOutOfStockVariants';
|
|
16
|
+
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
|
|
17
|
+
import BrowserPersistence from '../../util/simplePersistence';
|
|
16
18
|
|
|
17
19
|
const INITIAL_OPTION_CODES = new Map();
|
|
18
20
|
const INITIAL_OPTION_SELECTIONS = new Map();
|
|
@@ -257,7 +259,9 @@ export const useProductFullDetail = props => {
|
|
|
257
259
|
|
|
258
260
|
const isSupportedProductType = isSupported(productType);
|
|
259
261
|
|
|
260
|
-
const [{ cartId }] = useCartContext();
|
|
262
|
+
//const [{ cartId }] = useCartContext();
|
|
263
|
+
const [cartState, cartApi] = useCartContext();
|
|
264
|
+
const { cartId } = cartState;
|
|
261
265
|
const [{ isSignedIn }] = useUserContext();
|
|
262
266
|
const { formatMessage } = useIntl();
|
|
263
267
|
|
|
@@ -411,6 +415,42 @@ export const useProductFullDetail = props => {
|
|
|
411
415
|
return selectedOptions;
|
|
412
416
|
}, [attributeIdToValuesMap, optionSelections]);
|
|
413
417
|
|
|
418
|
+
// Cart creation wiring (same approach as useAddToCartButton.js)
|
|
419
|
+
const CREATE_CART_MUTATION = gql`
|
|
420
|
+
mutation createCart {
|
|
421
|
+
cartId: createEmptyCart
|
|
422
|
+
}
|
|
423
|
+
`;
|
|
424
|
+
|
|
425
|
+
const CART_DETAILS_QUERY = gql`
|
|
426
|
+
query checkUserIsAuthed($cartId: String!) {
|
|
427
|
+
cart(cart_id: $cartId) {
|
|
428
|
+
id
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
`;
|
|
432
|
+
|
|
433
|
+
const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
|
|
434
|
+
const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
|
|
435
|
+
|
|
436
|
+
const ensureCartId = useCallback(async () => {
|
|
437
|
+
let newCartId = cartId;
|
|
438
|
+
if (!newCartId) {
|
|
439
|
+
await cartApi.getCartDetails({
|
|
440
|
+
fetchCartId,
|
|
441
|
+
fetchCartDetails
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
newCartId = new BrowserPersistence().getItem('cartId');
|
|
445
|
+
if (!newCartId) {
|
|
446
|
+
throw new Error('Failed to create a new cart');
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return newCartId;
|
|
450
|
+
}, [cartId, cartApi, fetchCartId, fetchCartDetails]);
|
|
451
|
+
|
|
452
|
+
// Cart Creation ends
|
|
453
|
+
|
|
414
454
|
const handleAddToCart = useCallback(
|
|
415
455
|
async formValues => {
|
|
416
456
|
const { quantity } = formValues;
|
|
@@ -435,7 +475,7 @@ export const useProductFullDetail = props => {
|
|
|
435
475
|
|
|
436
476
|
if (isSupportedProductType) {
|
|
437
477
|
const variables = {
|
|
438
|
-
cartId,
|
|
478
|
+
cartId, // will be replaced by ensured cart id below
|
|
439
479
|
parentSku: payload.parentSku,
|
|
440
480
|
product: payload.item,
|
|
441
481
|
quantity: payload.quantity,
|
|
@@ -484,6 +524,10 @@ export const useProductFullDetail = props => {
|
|
|
484
524
|
}
|
|
485
525
|
|
|
486
526
|
try {
|
|
527
|
+
//Ensure cart exists *right before* mutation runs
|
|
528
|
+
const ensuredCartId = await ensureCartId();
|
|
529
|
+
variables.cartId = ensuredCartId;
|
|
530
|
+
|
|
487
531
|
await addProductToCart({ variables });
|
|
488
532
|
|
|
489
533
|
const selectedOptionsLabels =
|
|
@@ -498,7 +542,7 @@ export const useProductFullDetail = props => {
|
|
|
498
542
|
dispatch({
|
|
499
543
|
type: 'CART_ADD_ITEM',
|
|
500
544
|
payload: {
|
|
501
|
-
cartId,
|
|
545
|
+
cartId: ensuredCartId,
|
|
502
546
|
sku: product.sku,
|
|
503
547
|
name: product.name,
|
|
504
548
|
pricing: product.price,
|
|
@@ -527,7 +571,8 @@ export const useProductFullDetail = props => {
|
|
|
527
571
|
product,
|
|
528
572
|
productPrice,
|
|
529
573
|
productType,
|
|
530
|
-
selectedOptionsArray
|
|
574
|
+
selectedOptionsArray,
|
|
575
|
+
ensureCartId
|
|
531
576
|
]
|
|
532
577
|
);
|
|
533
578
|
|
|
@@ -98,6 +98,16 @@ export const useSignIn = props => {
|
|
|
98
98
|
try {
|
|
99
99
|
// Get source cart id (guest cart id).
|
|
100
100
|
const sourceCartId = cartId;
|
|
101
|
+
let hasSourceItems = false;
|
|
102
|
+
|
|
103
|
+
if (sourceCartId !== null) {
|
|
104
|
+
const { data: sourceCartData } = await fetchCartDetails({
|
|
105
|
+
variables: { cartId: sourceCartId },
|
|
106
|
+
fetchPolicy: 'network-only'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
hasSourceItems = sourceCartData?.cart?.items?.length > 0;
|
|
110
|
+
}
|
|
101
111
|
|
|
102
112
|
// Get recaptchaV3 data for login
|
|
103
113
|
const recaptchaData = await generateReCaptchaData();
|
|
@@ -127,14 +137,30 @@ export const useSignIn = props => {
|
|
|
127
137
|
});
|
|
128
138
|
const destinationCartId = await retrieveCartId();
|
|
129
139
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
destinationCartId,
|
|
134
|
-
sourceCartId
|
|
135
|
-
}
|
|
140
|
+
const { data: destCartData } = await fetchCartDetails({
|
|
141
|
+
variables: { cartId: destinationCartId },
|
|
142
|
+
fetchPolicy: 'network-only'
|
|
136
143
|
});
|
|
137
144
|
|
|
145
|
+
const hasDestinationItems =
|
|
146
|
+
destCartData?.cart?.items?.length > 0;
|
|
147
|
+
|
|
148
|
+
if (sourceCartId !== null && hasSourceItems) {
|
|
149
|
+
console.log('Merging guest cart into customer cart');
|
|
150
|
+
// Merge the guest cart into the customer cart.
|
|
151
|
+
await mergeCarts({
|
|
152
|
+
variables: {
|
|
153
|
+
destinationCartId,
|
|
154
|
+
sourceCartId
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
} else if (!hasSourceItems && !hasDestinationItems) {
|
|
158
|
+
console.log('Both carts empty → clearing local cart');
|
|
159
|
+
// Clear all cart/customer data from cache and redux.
|
|
160
|
+
await apolloClient.clearCacheData(apolloClient, 'cart');
|
|
161
|
+
await removeCart();
|
|
162
|
+
}
|
|
163
|
+
|
|
138
164
|
// Ensure old stores are updated with any new data.
|
|
139
165
|
|
|
140
166
|
await getUserDetails({ fetchUserDetails });
|
|
@@ -150,7 +176,9 @@ export const useSignIn = props => {
|
|
|
150
176
|
}
|
|
151
177
|
});
|
|
152
178
|
|
|
153
|
-
|
|
179
|
+
if (sourceCartId !== null && hasSourceItems) {
|
|
180
|
+
getCartDetails({ fetchCartId, fetchCartDetails });
|
|
181
|
+
}
|
|
154
182
|
|
|
155
183
|
if (
|
|
156
184
|
userOnOrderSuccess &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useLazyQuery } from '@apollo/client';
|
|
3
3
|
import mergeOperations from '../../util/shallowMerge';
|
|
4
4
|
import defaultOperations from './wishlist.gql';
|
|
@@ -17,15 +17,17 @@ export const useWishlist = (props = {}) => {
|
|
|
17
17
|
const [page, setPage] = useState(1);
|
|
18
18
|
const [isOpen, setIsOpen] = useState(!isCollapsed);
|
|
19
19
|
const [isFetchingMore, setIsFetchingMore] = useState(false);
|
|
20
|
+
const hasFetchedRef = useRef(false);
|
|
20
21
|
|
|
21
22
|
const [fetchWishlistItems, queryResult] = useLazyQuery(
|
|
22
23
|
operations.getCustomerWishlistItems,
|
|
23
24
|
{
|
|
24
|
-
fetchPolicy: 'cache-
|
|
25
|
+
fetchPolicy: 'cache-first',
|
|
25
26
|
nextFetchPolicy: 'cache-first',
|
|
26
27
|
variables: {
|
|
27
28
|
id,
|
|
28
|
-
currentPage: 1
|
|
29
|
+
currentPage: 1,
|
|
30
|
+
pageSize: 20
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
);
|
|
@@ -38,28 +40,84 @@ export const useWishlist = (props = {}) => {
|
|
|
38
40
|
const handleLoadMore = useCallback(async () => {
|
|
39
41
|
setIsFetchingMore(true);
|
|
40
42
|
const currentPage = page + 1;
|
|
41
|
-
await fetchMore({
|
|
42
|
-
variables: {
|
|
43
|
-
id,
|
|
44
|
-
currentPage
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
try {
|
|
45
|
+
await fetchMore({
|
|
46
|
+
variables: {
|
|
47
|
+
id,
|
|
48
|
+
currentPage,
|
|
49
|
+
pageSize: 20
|
|
50
|
+
},
|
|
51
|
+
updateQuery: (prevResult, { fetchMoreResult }) => {
|
|
52
|
+
if (!fetchMoreResult) {
|
|
53
|
+
return prevResult;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const prevWishlist = prevResult.customer.wishlist_v2;
|
|
57
|
+
const newWishlist = fetchMoreResult.customer.wishlist_v2;
|
|
58
|
+
|
|
59
|
+
if (prevWishlist.id !== newWishlist.id) {
|
|
60
|
+
return prevResult;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const prevItems = prevWishlist.items_v2.items || [];
|
|
64
|
+
const newItems = newWishlist.items_v2.items || [];
|
|
65
|
+
|
|
66
|
+
const existingIds = new Set(prevItems.map(item => item.id));
|
|
67
|
+
const uniqueNewItems = newItems.filter(
|
|
68
|
+
item => !existingIds.has(item.id)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
...prevResult,
|
|
73
|
+
customer: {
|
|
74
|
+
...prevResult.customer,
|
|
75
|
+
wishlist_v2: {
|
|
76
|
+
...prevWishlist,
|
|
77
|
+
items_v2: {
|
|
78
|
+
...prevWishlist.items_v2,
|
|
79
|
+
items: [...prevItems, ...uniqueNewItems]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
setPage(currentPage);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error('Error loading more wishlist items:', error);
|
|
90
|
+
} finally {
|
|
91
|
+
setIsFetchingMore(false);
|
|
92
|
+
}
|
|
50
93
|
}, [id, fetchMore, page]);
|
|
51
94
|
|
|
52
95
|
useEffect(() => {
|
|
53
|
-
|
|
54
|
-
|
|
96
|
+
if (itemsCount >= 1 && isOpen === true && !hasFetchedRef.current) {
|
|
97
|
+
hasFetchedRef.current = true;
|
|
55
98
|
fetchWishlistItems();
|
|
56
99
|
}
|
|
57
|
-
}, [itemsCount, isOpen, fetchWishlistItems
|
|
100
|
+
}, [itemsCount, isOpen, fetchWishlistItems]);
|
|
101
|
+
|
|
102
|
+
const items = useMemo(() => {
|
|
103
|
+
if (!data || !data.customer || !data.customer.wishlist_v2) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const allItems = data.customer.wishlist_v2.items_v2?.items || [];
|
|
108
|
+
|
|
109
|
+
const uniqueItems = [];
|
|
110
|
+
const seenIds = new Set();
|
|
111
|
+
|
|
112
|
+
for (const item of allItems) {
|
|
113
|
+
if (!seenIds.has(item.id)) {
|
|
114
|
+
seenIds.add(item.id);
|
|
115
|
+
uniqueItems.push(item);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
58
118
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
? data.customer.wishlist_v2.items_v2.items
|
|
62
|
-
: [];
|
|
119
|
+
return uniqueItems;
|
|
120
|
+
}, [data]);
|
|
63
121
|
|
|
64
122
|
return {
|
|
65
123
|
handleContentToggle,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
-
import { useMutation } from '@apollo/client';
|
|
2
|
+
import { gql, useMutation } from '@apollo/client';
|
|
3
3
|
|
|
4
4
|
import { useCartContext } from '@magento/peregrine/lib/context/cart';
|
|
5
|
+
import { useAwaitQuery } from '@magento/peregrine/lib/hooks/useAwaitQuery';
|
|
6
|
+
import BrowserPersistence from '../../util/simplePersistence';
|
|
5
7
|
import mergeOperations from '../../util/shallowMerge';
|
|
6
8
|
import defaultOperations from './wishlistItem.gql';
|
|
7
9
|
import { useEventingContext } from '../../context/eventing';
|
|
@@ -18,6 +20,20 @@ const mergeSupportedProductTypes = (supportedProductTypes = []) => {
|
|
|
18
20
|
return newSupportedProductTypes;
|
|
19
21
|
};
|
|
20
22
|
|
|
23
|
+
const CREATE_CART_MUTATION = gql`
|
|
24
|
+
mutation createCart {
|
|
25
|
+
cartId: createEmptyCart
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const CART_DETAILS_QUERY = gql`
|
|
30
|
+
query getCart($cartId: String!) {
|
|
31
|
+
cart(cart_id: $cartId) {
|
|
32
|
+
id
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
|
|
21
37
|
/**
|
|
22
38
|
* @function
|
|
23
39
|
*
|
|
@@ -61,7 +77,8 @@ export const useWishlistItem = props => {
|
|
|
61
77
|
removeProductsFromWishlistMutation
|
|
62
78
|
} = operations;
|
|
63
79
|
|
|
64
|
-
const [{ cartId }] = useCartContext();
|
|
80
|
+
//const [{ cartId }] = useCartContext();
|
|
81
|
+
const [{ cartId: existingCartId }, { getCartDetails }] = useCartContext();
|
|
65
82
|
|
|
66
83
|
const [isRemovalInProgress, setIsRemovalInProgress] = useState(false);
|
|
67
84
|
|
|
@@ -119,18 +136,26 @@ export const useWishlistItem = props => {
|
|
|
119
136
|
return item;
|
|
120
137
|
}, [configurableOptions, selectedConfigurableOptions, sku]);
|
|
121
138
|
|
|
139
|
+
// const [
|
|
140
|
+
// addWishlistItemToCart,
|
|
141
|
+
// {
|
|
142
|
+
// error: addWishlistItemToCartError,
|
|
143
|
+
// loading: addWishlistItemToCartLoading
|
|
144
|
+
// }
|
|
145
|
+
// ] = useMutation(addWishlistItemToCartMutation, {
|
|
146
|
+
// variables: {
|
|
147
|
+
// cartId,
|
|
148
|
+
// cartItem
|
|
149
|
+
// }
|
|
150
|
+
// });
|
|
151
|
+
|
|
122
152
|
const [
|
|
123
153
|
addWishlistItemToCart,
|
|
124
154
|
{
|
|
125
155
|
error: addWishlistItemToCartError,
|
|
126
156
|
loading: addWishlistItemToCartLoading
|
|
127
157
|
}
|
|
128
|
-
] = useMutation(addWishlistItemToCartMutation
|
|
129
|
-
variables: {
|
|
130
|
-
cartId,
|
|
131
|
-
cartItem
|
|
132
|
-
}
|
|
133
|
-
});
|
|
158
|
+
] = useMutation(addWishlistItemToCartMutation);
|
|
134
159
|
|
|
135
160
|
const [removeProductsFromWishlist] = useMutation(
|
|
136
161
|
removeProductsFromWishlistMutation,
|
|
@@ -169,13 +194,41 @@ export const useWishlistItem = props => {
|
|
|
169
194
|
}
|
|
170
195
|
);
|
|
171
196
|
|
|
197
|
+
const [fetchCartId] = useMutation(CREATE_CART_MUTATION);
|
|
198
|
+
const fetchCartDetails = useAwaitQuery(CART_DETAILS_QUERY);
|
|
199
|
+
|
|
200
|
+
const ensureCartId = useCallback(async () => {
|
|
201
|
+
let newCartId = existingCartId;
|
|
202
|
+
|
|
203
|
+
if (!newCartId) {
|
|
204
|
+
await getCartDetails({
|
|
205
|
+
fetchCartId,
|
|
206
|
+
fetchCartDetails
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
newCartId = new BrowserPersistence().getItem('cartId');
|
|
210
|
+
|
|
211
|
+
if (!newCartId) {
|
|
212
|
+
throw new Error('Failed to create a new cart');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return newCartId;
|
|
216
|
+
}, [existingCartId, getCartDetails, fetchCartId, fetchCartDetails]);
|
|
217
|
+
|
|
172
218
|
const handleAddToCart = useCallback(async () => {
|
|
173
219
|
if (
|
|
174
220
|
configurableOptions.length === 0 ||
|
|
175
221
|
selectedConfigurableOptions.length === configurableOptions.length
|
|
176
222
|
) {
|
|
177
223
|
try {
|
|
178
|
-
await
|
|
224
|
+
const ensuredCartId = await ensureCartId();
|
|
225
|
+
//await addWishlistItemToCart();
|
|
226
|
+
await addWishlistItemToCart({
|
|
227
|
+
variables: {
|
|
228
|
+
cartId: ensuredCartId,
|
|
229
|
+
cartItem
|
|
230
|
+
}
|
|
231
|
+
});
|
|
179
232
|
|
|
180
233
|
const selectedOptionsLabels =
|
|
181
234
|
selectedConfigurableOptions?.length > 0
|
|
@@ -190,7 +243,7 @@ export const useWishlistItem = props => {
|
|
|
190
243
|
dispatch({
|
|
191
244
|
type: 'CART_ADD_ITEM',
|
|
192
245
|
payload: {
|
|
193
|
-
cartId,
|
|
246
|
+
cartId: ensuredCartId,
|
|
194
247
|
sku: item.product.sku,
|
|
195
248
|
name: item.product.name,
|
|
196
249
|
pricing: item.product.price,
|
|
@@ -215,9 +268,11 @@ export const useWishlistItem = props => {
|
|
|
215
268
|
}
|
|
216
269
|
}, [
|
|
217
270
|
addWishlistItemToCart,
|
|
218
|
-
cartId,
|
|
271
|
+
//cartId,
|
|
272
|
+
cartItem,
|
|
219
273
|
configurableOptions.length,
|
|
220
274
|
dispatch,
|
|
275
|
+
ensureCartId,
|
|
221
276
|
item,
|
|
222
277
|
onOpenAddToCartDialog,
|
|
223
278
|
selectedConfigurableOptions
|
|
@@ -17,12 +17,12 @@ export const GET_CUSTOMER_WISHLIST = gql`
|
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
19
|
export const GET_CUSTOMER_WISHLIST_ITEMS = gql`
|
|
20
|
-
query getCustomerWishlist($id: ID!, $currentPage: Int) {
|
|
20
|
+
query getCustomerWishlist($id: ID!, $currentPage: Int, $pageSize: Int) {
|
|
21
21
|
# eslint-disable-next-line @graphql-eslint/require-id-when-available
|
|
22
22
|
customer {
|
|
23
23
|
wishlist_v2(id: $id) {
|
|
24
24
|
id
|
|
25
|
-
items_v2(currentPage: $currentPage) {
|
|
25
|
+
items_v2(currentPage: $currentPage, pageSize: $pageSize) {
|
|
26
26
|
items {
|
|
27
27
|
id
|
|
28
28
|
...WishlistItemFragment
|
|
@@ -18,8 +18,6 @@ export const getOutOfStockVariants = (
|
|
|
18
18
|
isOutOfStockProductDisplayed
|
|
19
19
|
) => {
|
|
20
20
|
const isConfigurable = isProductConfigurable(product);
|
|
21
|
-
const singeOptionSelected =
|
|
22
|
-
singleOptionSelection && singleOptionSelection.size === 1;
|
|
23
21
|
const outOfStockIndexes = [];
|
|
24
22
|
|
|
25
23
|
if (isConfigurable) {
|
|
@@ -32,6 +30,14 @@ export const getOutOfStockVariants = (
|
|
|
32
30
|
? variants
|
|
33
31
|
: variantsIfOutOfStockProductsNotDisplayed;
|
|
34
32
|
|
|
33
|
+
if (!variants || variants.length === 0) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!variants[0] || !variants[0].attributes) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
const numberOfVariations = variants[0].attributes.length;
|
|
36
42
|
|
|
37
43
|
// If only one pair of variations, display out of stock variations before option selection
|
|
@@ -45,18 +51,14 @@ export const getOutOfStockVariants = (
|
|
|
45
51
|
);
|
|
46
52
|
return outOfStockIndex;
|
|
47
53
|
} else {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
value => !!value
|
|
52
|
-
).length > 1;
|
|
53
|
-
const selectedIndexes = Array.from(
|
|
54
|
-
optionSelections.values()
|
|
55
|
-
).flat();
|
|
54
|
+
const selectedIndexes = Array.from(
|
|
55
|
+
optionSelections.values()
|
|
56
|
+
).filter(value => !!value);
|
|
56
57
|
|
|
58
|
+
if (selectedIndexes.length > 0) {
|
|
57
59
|
const items = findAllMatchingVariants({
|
|
58
60
|
optionCodes,
|
|
59
|
-
singleOptionSelection,
|
|
61
|
+
singleOptionSelection: optionSelections,
|
|
60
62
|
variants
|
|
61
63
|
});
|
|
62
64
|
const outOfStockItemsIndexes = getOutOfStockIndexes(items);
|
|
@@ -70,15 +72,14 @@ export const getOutOfStockVariants = (
|
|
|
70
72
|
const differentIndexes = indexes.filter(
|
|
71
73
|
num => !selectedIndexes.includes(num)
|
|
72
74
|
);
|
|
73
|
-
if (sameIndexes.length
|
|
75
|
+
if (sameIndexes.length > 0) {
|
|
74
76
|
outOfStockIndexes.push(differentIndexes);
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
// Display all possible out of stock swatches with current selections, when all groups of swatches are selected
|
|
78
80
|
if (
|
|
79
|
-
|
|
80
|
-
!selectedIndexes.includes(undefined)
|
|
81
|
-
selectedIndexes.length === optionCodes.size
|
|
81
|
+
selectedIndexes.length === optionCodes.size &&
|
|
82
|
+
!selectedIndexes.includes(undefined)
|
|
82
83
|
) {
|
|
83
84
|
const selectedIndexesCombinations = getCombinations(
|
|
84
85
|
selectedIndexes,
|
|
@@ -96,7 +97,7 @@ export const getOutOfStockVariants = (
|
|
|
96
97
|
)
|
|
97
98
|
);
|
|
98
99
|
const curItems = findAllMatchingVariants({
|
|
99
|
-
optionCodes
|
|
100
|
+
optionCodes,
|
|
100
101
|
singleOptionSelection: curOption,
|
|
101
102
|
variants: variants
|
|
102
103
|
});
|
|
@@ -107,8 +108,11 @@ export const getOutOfStockVariants = (
|
|
|
107
108
|
}
|
|
108
109
|
return oosIndexes;
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
+
} else {
|
|
112
|
+
return [];
|
|
111
113
|
}
|
|
114
|
+
|
|
115
|
+
return outOfStockIndexes;
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
return [];
|
|
@@ -7,6 +7,8 @@ import { getOutOfStockIndexes } from '@magento/peregrine/lib/util/getOutOfStockI
|
|
|
7
7
|
import { createProductVariants } from '@magento/peregrine/lib/util/createProductVariants';
|
|
8
8
|
import { getCombinations } from '@magento/peregrine/lib/util/getCombinations';
|
|
9
9
|
|
|
10
|
+
const OUT_OF_STOCK_CODE = 'OUT_OF_STOCK';
|
|
11
|
+
|
|
10
12
|
export const getOutOfStockVariantsWithInitialSelection = (
|
|
11
13
|
product,
|
|
12
14
|
configurableOptionCodes,
|
|
@@ -14,50 +16,100 @@ export const getOutOfStockVariantsWithInitialSelection = (
|
|
|
14
16
|
configItem,
|
|
15
17
|
isOutOfStockProductDisplayed
|
|
16
18
|
) => {
|
|
17
|
-
if (configItem
|
|
19
|
+
if (configItem) {
|
|
20
|
+
const selectedIndexes = Array.from(
|
|
21
|
+
multipleOptionSelections.values()
|
|
22
|
+
).filter(value => !!value);
|
|
23
|
+
|
|
18
24
|
let variants = product.variants;
|
|
19
25
|
const variantsIfOutOfStockProductsNotDisplayed = createProductVariants(
|
|
20
|
-
|
|
26
|
+
product
|
|
21
27
|
);
|
|
22
28
|
//If out of stock products is set to not displayed, use the variants created
|
|
23
29
|
variants = isOutOfStockProductDisplayed
|
|
24
30
|
? variants
|
|
25
31
|
: variantsIfOutOfStockProductsNotDisplayed;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
|
|
33
|
+
if (!variants || variants.length === 0) {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!variants[0] || !variants[0].attributes) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const numberOfVariations = variants[0].attributes.length;
|
|
42
|
+
|
|
43
|
+
if (numberOfVariations === 1) {
|
|
44
|
+
const outOfStockOptions = variants.filter(
|
|
45
|
+
variant => variant.product.stock_status === OUT_OF_STOCK_CODE
|
|
37
46
|
);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
47
|
+
|
|
48
|
+
const outOfStockIndex = outOfStockOptions.map(option =>
|
|
49
|
+
option.attributes.map(attribute => attribute.value_index)
|
|
50
|
+
);
|
|
51
|
+
return outOfStockIndex;
|
|
52
|
+
} else {
|
|
53
|
+
const outOfStockIndexes = [];
|
|
54
|
+
|
|
55
|
+
if (selectedIndexes.length > 0) {
|
|
56
|
+
const items = findAllMatchingVariants({
|
|
48
57
|
optionCodes: configurableOptionCodes,
|
|
49
|
-
singleOptionSelection:
|
|
50
|
-
variants
|
|
58
|
+
singleOptionSelection: multipleOptionSelections,
|
|
59
|
+
variants
|
|
51
60
|
});
|
|
52
61
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
const outOfStockItemsIndexes = getOutOfStockIndexes(items);
|
|
63
|
+
|
|
64
|
+
for (const indexes of outOfStockItemsIndexes) {
|
|
65
|
+
const sameIndexes = indexes.filter(num =>
|
|
66
|
+
selectedIndexes.includes(num)
|
|
67
|
+
);
|
|
68
|
+
const differentIndexes = indexes.filter(
|
|
69
|
+
num => !selectedIndexes.includes(num)
|
|
70
|
+
);
|
|
56
71
|
|
|
57
|
-
|
|
72
|
+
if (sameIndexes.length > 0) {
|
|
73
|
+
outOfStockIndexes.push(differentIndexes);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
selectedIndexes.length === configurableOptionCodes.size &&
|
|
79
|
+
!selectedIndexes.includes(undefined)
|
|
80
|
+
) {
|
|
81
|
+
const selectedIndexesCombinations = getCombinations(
|
|
82
|
+
selectedIndexes,
|
|
83
|
+
selectedIndexes.length - 1
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const oosIndexes = [];
|
|
87
|
+
for (const option of selectedIndexesCombinations) {
|
|
88
|
+
const curOption = new Map(
|
|
89
|
+
[...multipleOptionSelections].filter(
|
|
90
|
+
([key, val]) => (
|
|
91
|
+
option.includes(key), option.includes(val)
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
const curItems = findAllMatchingVariants({
|
|
96
|
+
optionCodes: configurableOptionCodes,
|
|
97
|
+
singleOptionSelection: curOption,
|
|
98
|
+
variants: variants
|
|
99
|
+
});
|
|
100
|
+
const outOfStockIndex = getOutOfStockIndexes(curItems)
|
|
101
|
+
?.flat()
|
|
102
|
+
.filter(idx => !selectedIndexes.includes(idx));
|
|
103
|
+
oosIndexes.push(outOfStockIndex);
|
|
104
|
+
}
|
|
105
|
+
return oosIndexes;
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
return [];
|
|
58
109
|
}
|
|
59
|
-
|
|
110
|
+
|
|
111
|
+
return outOfStockIndexes;
|
|
60
112
|
}
|
|
61
|
-
return [];
|
|
62
113
|
}
|
|
114
|
+
return [];
|
|
63
115
|
};
|