@magento/peregrine 11.0.0-beta.1 → 12.0.0-alpha.3
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/magentoGqlCacheLink.js +59 -0
- package/lib/List/item.js +12 -9
- package/lib/List/list.js +10 -7
- package/lib/Price/price.js +0 -1
- package/lib/context/cart.js +9 -10
- package/lib/hooks/hook-wrappers/useInformedFieldStateWrapper.js +27 -0
- package/lib/hooks/useDelayedTransition.js +127 -0
- package/lib/hooks/useDetectScrollWidth.js +77 -0
- package/lib/hooks/useInternalLink.js +21 -0
- package/lib/hooks/useIntersectionObserver.js +7 -0
- package/lib/hooks/useIsInViewport.js +44 -0
- package/lib/store/actions/app/actions.js +2 -1
- package/lib/store/reducers/app.js +8 -1
- package/lib/talons/AccountInformationPage/useAccountInformationPage.js +0 -1
- package/lib/talons/Adapter/useAdapter.js +23 -3
- package/lib/talons/AddressBookPage/useAddressBookPage.js +0 -10
- package/lib/talons/Breadcrumbs/breadcrumbs.gql.js +11 -2
- package/lib/talons/Breadcrumbs/useBreadcrumbs.js +19 -5
- package/lib/talons/CartPage/GiftCards/giftCardFragments.gql.ee.js +14 -0
- package/lib/talons/CartPage/GiftCards/giftCardFragments.gql.js +8 -0
- package/lib/talons/CartPage/GiftCards/giftCardQueries.gql.ee.js +73 -0
- package/lib/talons/CartPage/GiftCards/useGiftCards.js +25 -16
- package/lib/talons/CartPage/PriceAdjustments/CouponCode/couponCode.gql.js +56 -0
- package/lib/talons/CartPage/PriceAdjustments/CouponCode/couponCodeFragments.gql.js +10 -0
- package/lib/talons/CartPage/PriceAdjustments/{useCouponCode.js → CouponCode/useCouponCode.js} +10 -6
- package/lib/talons/CartPage/{GiftOptions → PriceAdjustments/GiftOptions}/client-schema.graphql +0 -0
- package/lib/talons/CartPage/PriceAdjustments/GiftOptions/giftOptions.gql.js +21 -0
- package/lib/talons/CartPage/{GiftOptions → PriceAdjustments/GiftOptions}/useGiftOptions.js +5 -3
- package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/shippingMethods.gql.js +43 -0
- package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/shippingMethodsFragments.gql.js +60 -0
- package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/useShippingForm.js +8 -9
- package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/useShippingMethods.js +7 -5
- package/lib/talons/CartPage/PriceAdjustments/ShippingMethods/useShippingRadios.js +1 -1
- package/lib/talons/CartPage/PriceSummary/priceSummary.gql.js +16 -0
- package/lib/talons/CartPage/PriceSummary/usePriceSummary.js +6 -5
- package/lib/talons/CartPage/ProductListing/EditModal/productForm.gql.js +78 -0
- package/lib/talons/CartPage/ProductListing/EditModal/productFormFragment.gql.js +47 -0
- package/lib/talons/CartPage/ProductListing/EditModal/useProductForm.js +18 -8
- package/lib/talons/CartPage/ProductListing/product.gql.js +4 -3
- package/lib/talons/CartPage/ProductListing/productListing.gql.ce.js +13 -1
- package/lib/talons/CartPage/ProductListing/productListing.gql.ee.js +13 -1
- package/lib/talons/CartPage/ProductListing/productListingFragments.gql.js +52 -0
- package/lib/talons/CartPage/ProductListing/useProduct.js +22 -18
- package/lib/talons/CartPage/ProductListing/useProductListing.js +8 -13
- package/lib/talons/CartPage/ProductListing/useQuantity.js +2 -1
- package/lib/talons/CartPage/cartPage.gql.js +16 -0
- package/lib/talons/CartPage/cartPageFragments.gql.js +21 -0
- package/lib/talons/CartPage/useCartPage.js +7 -6
- package/lib/talons/CategoryList/categoryList.gql.js +11 -2
- package/lib/talons/CategoryList/useCategoryList.js +8 -1
- package/lib/talons/CategoryList/useCategoryTile.js +10 -4
- package/lib/talons/CategoryTree/categoryTree.gql.js +11 -2
- package/lib/talons/CategoryTree/useCategoryTree.js +12 -3
- package/lib/talons/CheckoutPage/AddressBook/addressBook.gql.js +34 -0
- package/lib/talons/CheckoutPage/AddressBook/addressBookFragments.gql.js +31 -0
- package/lib/talons/CheckoutPage/AddressBook/useAddressBook.js +16 -8
- package/lib/talons/CheckoutPage/PaymentInformation/braintreeSummary.gql.js +1 -1
- package/lib/talons/CheckoutPage/PaymentInformation/editModal.gql.js +16 -0
- package/lib/talons/CheckoutPage/PaymentInformation/paymentInformation.gql.js +4 -8
- package/lib/talons/CheckoutPage/PaymentInformation/paymentMethods.gql.js +17 -0
- package/lib/talons/CheckoutPage/PaymentInformation/useBraintreeSummary.js +1 -1
- package/lib/talons/CheckoutPage/PaymentInformation/useEditModal.js +6 -5
- package/lib/talons/CheckoutPage/PaymentInformation/usePaymentInformation.js +22 -16
- package/lib/talons/CheckoutPage/PaymentInformation/usePaymentMethods.js +6 -3
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/customerForm.gql.js +55 -0
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/guestForm.gql.js +44 -0
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/useCustomerForm.js +11 -14
- package/lib/talons/CheckoutPage/ShippingInformation/AddressForm/useGuestForm.js +6 -7
- package/lib/talons/CheckoutPage/ShippingInformation/shippingInformation.gql.js +54 -0
- package/lib/talons/CheckoutPage/ShippingInformation/shippingInformationFragments.gql.js +25 -0
- package/lib/talons/CheckoutPage/ShippingInformation/useShippingInformation.js +11 -6
- package/lib/talons/CheckoutPage/ShippingMethod/shippingMethod.gql.js +64 -0
- package/lib/talons/CheckoutPage/ShippingMethod/shippingMethodFragments.gql.js +64 -0
- package/lib/talons/CheckoutPage/{useShippingMethod.js → ShippingMethod/useShippingMethod.js} +11 -8
- package/lib/talons/Cms/cmsPage.gql.js +2 -2
- package/lib/talons/Cms/useCmsPage.js +2 -2
- package/lib/talons/CommunicationsPage/useCommunicationsPage.js +1 -2
- package/lib/talons/CreateAccount/createAccount.gql.js +3 -0
- package/lib/talons/CreateAccount/useCreateAccount.js +2 -4
- package/lib/talons/CreateAccountPage/useCreateAccountPage.js +38 -9
- package/lib/talons/FilterModal/useFilterList.js +17 -3
- package/lib/talons/FilterModal/useFilterModal.js +4 -5
- package/lib/talons/FilterSidebar/useFilterSidebar.js +4 -5
- package/lib/talons/ForgotPasswordPage/useForgotPasswordPage.js +46 -0
- package/lib/talons/FormError/useFormError.js +10 -3
- package/lib/talons/Gallery/__fixtures__/apolloMocks.js +8 -6
- package/lib/talons/Gallery/addToCart.gql.js +17 -0
- package/lib/talons/Gallery/gallery.gql.ce.js +4 -3
- package/lib/talons/Gallery/gallery.gql.ee.js +4 -3
- package/lib/talons/Gallery/useAddToCartButton.js +81 -0
- package/lib/talons/Gallery/useGallery.js +4 -7
- package/lib/talons/Gallery/useGalleryItem.js +7 -1
- package/lib/talons/Header/useCartTrigger.js +14 -7
- package/lib/talons/Link/useLink.js +68 -0
- package/lib/talons/MagentoRoute/magentoRoute.gql.js +12 -3
- package/lib/talons/MagentoRoute/useMagentoRoute.js +115 -30
- package/lib/talons/MegaMenu/megaMenu.gql.js +10 -4
- package/lib/talons/MegaMenu/useMegaMenu.js +61 -11
- package/lib/talons/MegaMenu/useMegaMenuItem.js +61 -0
- package/lib/talons/MegaMenu/useSubMenu.js +20 -0
- package/lib/talons/MiniCart/ProductList/productListFragments.gql.js +0 -1
- package/lib/talons/MiniCart/miniCart.gql.js +4 -3
- package/lib/talons/MiniCart/useMiniCart.js +15 -12
- package/lib/talons/Navigation/useNavigation.js +6 -1
- package/lib/talons/OrderHistoryPage/orderRow.gql.js +0 -1
- package/lib/talons/OrderHistoryPage/useOrderHistoryPage.js +2 -14
- package/lib/talons/PageLoadingIndicator/usePageLoadingIndicator.js +52 -0
- package/lib/talons/Postcode/usePostcode.js +2 -1
- package/lib/talons/ProductFullDetail/useProductFullDetail.js +30 -5
- package/lib/talons/Region/useRegion.js +12 -10
- package/lib/talons/RootComponents/Category/categoryFragments.gql.js +5 -4
- package/lib/talons/RootComponents/Product/productDetailFragment.gql.js +7 -0
- package/lib/talons/SavedPaymentsPage/useSavedPaymentsPage.js +1 -11
- package/lib/talons/SearchBar/useAutocomplete.js +1 -1
- package/lib/talons/SearchBar/useSearchField.js +2 -1
- package/lib/talons/SearchBar/useSuggestedCategory.js +4 -6
- package/lib/talons/SearchPage/searchPage.gql.js +10 -9
- package/lib/talons/SignIn/signIn.gql.js +3 -0
- package/lib/talons/SignInPage/useSignInPage.js +63 -0
- package/lib/talons/Wishlist/AddToListButton/helpers/useSingleWishlist.js +2 -2
- package/lib/talons/Wishlist/AddToListButton/useAddToListButton.ee.js +2 -1
- package/lib/talons/WishlistPage/useActionMenu.js +39 -5
- package/lib/talons/WishlistPage/useWishlist.js +4 -4
- package/lib/talons/WishlistPage/useWishlistPage.js +3 -11
- package/lib/talons/WishlistPage/wishlist.gql.js +1 -1
- package/lib/talons/WishlistPage/wishlistConfig.gql.ce.js +14 -0
- package/lib/talons/WishlistPage/wishlistConfig.gql.ee.js +15 -0
- package/lib/targets/peregrine-declare.js +0 -4
- package/lib/util/deriveErrorMessage.js +12 -6
- package/lib/util/images.js +3 -2
- package/lib/util/isSupportedProductType.js +5 -0
- package/lib/util/magentoRouteData.js +9 -0
- package/package.json +8 -8
|
@@ -33,7 +33,7 @@ export const useMiniCart = props => {
|
|
|
33
33
|
const {
|
|
34
34
|
removeItemMutation,
|
|
35
35
|
miniCartQuery,
|
|
36
|
-
|
|
36
|
+
getStoreConfigQuery
|
|
37
37
|
} = operations;
|
|
38
38
|
|
|
39
39
|
const [{ cartId }] = useCartContext();
|
|
@@ -49,19 +49,21 @@ export const useMiniCart = props => {
|
|
|
49
49
|
}
|
|
50
50
|
);
|
|
51
51
|
|
|
52
|
-
const { data:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
fetchPolicy: 'cache-and-network'
|
|
56
|
-
}
|
|
57
|
-
);
|
|
52
|
+
const { data: storeConfigData } = useQuery(getStoreConfigQuery, {
|
|
53
|
+
fetchPolicy: 'cache-and-network'
|
|
54
|
+
});
|
|
58
55
|
|
|
59
56
|
const configurableThumbnailSource = useMemo(() => {
|
|
60
|
-
if (
|
|
61
|
-
return
|
|
62
|
-
|
|
57
|
+
if (storeConfigData) {
|
|
58
|
+
return storeConfigData.storeConfig.configurable_thumbnail_source;
|
|
59
|
+
}
|
|
60
|
+
}, [storeConfigData]);
|
|
61
|
+
|
|
62
|
+
const storeUrlSuffix = useMemo(() => {
|
|
63
|
+
if (storeConfigData) {
|
|
64
|
+
return storeConfigData.storeConfig.product_url_suffix;
|
|
63
65
|
}
|
|
64
|
-
}, [
|
|
66
|
+
}, [storeConfigData]);
|
|
65
67
|
|
|
66
68
|
const [
|
|
67
69
|
removeItem,
|
|
@@ -135,6 +137,7 @@ export const useMiniCart = props => {
|
|
|
135
137
|
productList,
|
|
136
138
|
subTotal,
|
|
137
139
|
totalQuantity,
|
|
138
|
-
configurableThumbnailSource
|
|
140
|
+
configurableThumbnailSource,
|
|
141
|
+
storeUrlSuffix
|
|
139
142
|
};
|
|
140
143
|
};
|
|
@@ -6,6 +6,7 @@ import { useAppContext } from '../../context/app';
|
|
|
6
6
|
import { useCatalogContext } from '../../context/catalog';
|
|
7
7
|
import { useUserContext } from '../../context/user';
|
|
8
8
|
import { useAwaitQuery } from '../../hooks/useAwaitQuery';
|
|
9
|
+
import useInternalLink from '../../hooks/useInternalLink';
|
|
9
10
|
|
|
10
11
|
import DEFAULT_OPERATIONS from './navigation.gql';
|
|
11
12
|
|
|
@@ -76,9 +77,13 @@ export const useNavigation = (props = {}) => {
|
|
|
76
77
|
}
|
|
77
78
|
}, [category, closeDrawer, isTopLevel, view]);
|
|
78
79
|
|
|
80
|
+
const { setShimmerType } = useInternalLink('category');
|
|
81
|
+
|
|
79
82
|
const handleClose = useCallback(() => {
|
|
80
83
|
closeDrawer();
|
|
81
|
-
|
|
84
|
+
// Sets next root component to show proper loading effect
|
|
85
|
+
setShimmerType();
|
|
86
|
+
}, [closeDrawer, setShimmerType]);
|
|
82
87
|
|
|
83
88
|
// create callbacks for local state
|
|
84
89
|
const showCreateAccount = useCallback(() => {
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import { useHistory } from 'react-router-dom';
|
|
3
2
|
import { useQuery } from '@apollo/client';
|
|
4
3
|
|
|
4
|
+
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
5
|
+
import { deriveErrorMessage } from '@magento/peregrine/lib/util/deriveErrorMessage';
|
|
5
6
|
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
6
7
|
|
|
7
|
-
import { useAppContext } from '../../context/app';
|
|
8
|
-
import { useUserContext } from '../../context/user';
|
|
9
|
-
import { deriveErrorMessage } from '../../util/deriveErrorMessage';
|
|
10
|
-
|
|
11
8
|
import DEFAULT_OPERATIONS from './orderHistoryPage.gql';
|
|
12
9
|
|
|
13
10
|
const PAGE_SIZE = 10;
|
|
@@ -22,8 +19,6 @@ export const useOrderHistoryPage = (props = {}) => {
|
|
|
22
19
|
actions: { setPageLoading }
|
|
23
20
|
}
|
|
24
21
|
] = useAppContext();
|
|
25
|
-
const history = useHistory();
|
|
26
|
-
const [{ isSignedIn }] = useUserContext();
|
|
27
22
|
|
|
28
23
|
const [pageSize, setPageSize] = useState(PAGE_SIZE);
|
|
29
24
|
const [searchText, setSearchText] = useState('');
|
|
@@ -88,13 +83,6 @@ export const useOrderHistoryPage = (props = {}) => {
|
|
|
88
83
|
return null;
|
|
89
84
|
}, [orderData]);
|
|
90
85
|
|
|
91
|
-
// If the user is no longer signed in, redirect to the home page.
|
|
92
|
-
useEffect(() => {
|
|
93
|
-
if (!isSignedIn) {
|
|
94
|
-
history.push('/');
|
|
95
|
-
}
|
|
96
|
-
}, [history, isSignedIn]);
|
|
97
|
-
|
|
98
86
|
// Update the page indicator if the GraphQL query is in flight.
|
|
99
87
|
useEffect(() => {
|
|
100
88
|
setPageLoading(isBackgroundLoading);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useAppContext } from '../../context/app';
|
|
3
|
+
|
|
4
|
+
const GROUP_LOADING_DELAY = 750;
|
|
5
|
+
|
|
6
|
+
export default () => {
|
|
7
|
+
const [{ isPageLoading }] = useAppContext();
|
|
8
|
+
const doneTimeoutRef = useRef();
|
|
9
|
+
const [loadingState, setLoadingState] = useState('off');
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (isPageLoading) {
|
|
13
|
+
setLoadingState('loading');
|
|
14
|
+
} else if (
|
|
15
|
+
typeof clearTimeout !== 'undefined' &&
|
|
16
|
+
typeof setTimeout !== 'undefined'
|
|
17
|
+
) {
|
|
18
|
+
setLoadingState('done');
|
|
19
|
+
|
|
20
|
+
if (doneTimeoutRef && doneTimeoutRef.current !== null) {
|
|
21
|
+
clearTimeout(doneTimeoutRef.current);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
doneTimeoutRef.current = setTimeout(() => {
|
|
25
|
+
setLoadingState(currentLoadingState => {
|
|
26
|
+
if (currentLoadingState === 'loading') {
|
|
27
|
+
return 'loading';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return 'off';
|
|
31
|
+
});
|
|
32
|
+
}, GROUP_LOADING_DELAY);
|
|
33
|
+
} else {
|
|
34
|
+
setLoadingState('off');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return () => {
|
|
38
|
+
if (
|
|
39
|
+
typeof clearTimeout !== 'undefined' &&
|
|
40
|
+
doneTimeoutRef &&
|
|
41
|
+
doneTimeoutRef.current !== null
|
|
42
|
+
) {
|
|
43
|
+
clearTimeout(doneTimeoutRef.current);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}, [isPageLoading, doneTimeoutRef]);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
isPageLoading,
|
|
50
|
+
loadingState
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
|
-
import { useFieldApi
|
|
2
|
+
import { useFieldApi } from 'informed';
|
|
3
|
+
import useFieldState from '@magento/peregrine/lib/hooks/hook-wrappers/useInformedFieldStateWrapper';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The usePostcode talon handles logic for resetting the postcode field value when the country changes.
|
|
@@ -7,12 +7,14 @@ import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
|
7
7
|
import { appendOptionsToPayload } from '@magento/peregrine/lib/util/appendOptionsToPayload';
|
|
8
8
|
import { findMatchingVariant } from '@magento/peregrine/lib/util/findMatchingProductVariant';
|
|
9
9
|
import { isProductConfigurable } from '@magento/peregrine/lib/util/isProductConfigurable';
|
|
10
|
+
import { isSupportedProductType as isSupported } from '@magento/peregrine/lib/util/isSupportedProductType';
|
|
10
11
|
import { deriveErrorMessage } from '../../util/deriveErrorMessage';
|
|
11
12
|
import mergeOperations from '../../util/shallowMerge';
|
|
12
13
|
import defaultOperations from './productFullDetail.gql';
|
|
13
14
|
|
|
14
15
|
const INITIAL_OPTION_CODES = new Map();
|
|
15
16
|
const INITIAL_OPTION_SELECTIONS = new Map();
|
|
17
|
+
const OUT_OF_STOCK_CODE = 'OUT_OF_STOCK';
|
|
16
18
|
|
|
17
19
|
const deriveOptionCodesFromProduct = product => {
|
|
18
20
|
// If this is a simple product it has no option codes.
|
|
@@ -63,6 +65,25 @@ const getIsMissingOptions = (product, optionSelections) => {
|
|
|
63
65
|
return numProductSelections < numProductOptions;
|
|
64
66
|
};
|
|
65
67
|
|
|
68
|
+
const getIsOutOfStock = (product, optionCodes, optionSelections) => {
|
|
69
|
+
const { stock_status, variants } = product;
|
|
70
|
+
const isConfigurable = isProductConfigurable(product);
|
|
71
|
+
const optionsSelected =
|
|
72
|
+
Array.from(optionSelections.values()).filter(value => !!value).length >
|
|
73
|
+
0;
|
|
74
|
+
|
|
75
|
+
if (isConfigurable && optionsSelected) {
|
|
76
|
+
const item = findMatchingVariant({
|
|
77
|
+
optionCodes,
|
|
78
|
+
optionSelections,
|
|
79
|
+
variants
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return item.product.stock_status === OUT_OF_STOCK_CODE;
|
|
83
|
+
}
|
|
84
|
+
return stock_status === OUT_OF_STOCK_CODE;
|
|
85
|
+
};
|
|
86
|
+
|
|
66
87
|
const getMediaGalleryEntries = (product, optionCodes, optionSelections) => {
|
|
67
88
|
let value = [];
|
|
68
89
|
|
|
@@ -149,8 +170,6 @@ const getConfigPrice = (product, optionCodes, optionSelections) => {
|
|
|
149
170
|
return value;
|
|
150
171
|
};
|
|
151
172
|
|
|
152
|
-
const SUPPORTED_PRODUCT_TYPES = ['SimpleProduct', 'ConfigurableProduct'];
|
|
153
|
-
|
|
154
173
|
/**
|
|
155
174
|
* @param {GraphQLDocument} props.addConfigurableProductToCartMutation - configurable product mutation
|
|
156
175
|
* @param {GraphQLDocument} props.addSimpleProductToCartMutation - configurable product mutation
|
|
@@ -185,9 +204,7 @@ export const useProductFullDetail = props => {
|
|
|
185
204
|
|
|
186
205
|
const productType = product.__typename;
|
|
187
206
|
|
|
188
|
-
const isSupportedProductType =
|
|
189
|
-
productType
|
|
190
|
-
);
|
|
207
|
+
const isSupportedProductType = isSupported(productType);
|
|
191
208
|
|
|
192
209
|
const [{ cartId }] = useCartContext();
|
|
193
210
|
const [{ isSignedIn }] = useUserContext();
|
|
@@ -248,6 +265,12 @@ export const useProductFullDetail = props => {
|
|
|
248
265
|
() => getIsMissingOptions(product, optionSelections),
|
|
249
266
|
[product, optionSelections]
|
|
250
267
|
);
|
|
268
|
+
|
|
269
|
+
const isOutOfStock = useMemo(
|
|
270
|
+
() => getIsOutOfStock(product, optionCodes, optionSelections),
|
|
271
|
+
[product, optionCodes, optionSelections]
|
|
272
|
+
);
|
|
273
|
+
|
|
251
274
|
const mediaGalleryEntries = useMemo(
|
|
252
275
|
() => getMediaGalleryEntries(product, optionCodes, optionSelections),
|
|
253
276
|
[product, optionCodes, optionSelections]
|
|
@@ -445,7 +468,9 @@ export const useProductFullDetail = props => {
|
|
|
445
468
|
errorMessage: derivedErrorMessage,
|
|
446
469
|
handleAddToCart,
|
|
447
470
|
handleSelectionChange,
|
|
471
|
+
isOutOfStock,
|
|
448
472
|
isAddToCartDisabled:
|
|
473
|
+
isOutOfStock ||
|
|
449
474
|
isMissingOptions ||
|
|
450
475
|
isAddConfigurableLoading ||
|
|
451
476
|
isAddSimpleLoading ||
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
2
|
import { useQuery } from '@apollo/client';
|
|
3
|
-
import { useFieldApi
|
|
3
|
+
import { useFieldApi } from 'informed';
|
|
4
|
+
import useFieldState from '@magento/peregrine/lib/hooks/hook-wrappers/useInformedFieldStateWrapper';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* The useRegion talon handles logic for:
|
|
@@ -33,24 +34,25 @@ export const useRegion = props => {
|
|
|
33
34
|
const regionInputFieldApi = useFieldApi(fieldInput);
|
|
34
35
|
const regionSelectFieldApi = useFieldApi(fieldSelect);
|
|
35
36
|
|
|
37
|
+
const { data, loading } = useQuery(getRegionsQuery, {
|
|
38
|
+
variables: { countryCode: country },
|
|
39
|
+
skip: !country
|
|
40
|
+
});
|
|
41
|
+
|
|
36
42
|
// Reset region value when country changes. Because of how Informed sets
|
|
37
43
|
// initialValues, we want to skip the first state change of the value being
|
|
38
44
|
// initialized.
|
|
39
45
|
useEffect(() => {
|
|
40
|
-
if (country) {
|
|
46
|
+
if (country && !loading) {
|
|
41
47
|
if (hasInitialized.current) {
|
|
42
|
-
regionInputFieldApi.exists() && regionInputFieldApi.
|
|
43
|
-
regionSelectFieldApi.exists() &&
|
|
48
|
+
regionInputFieldApi.exists() && regionInputFieldApi.setValue();
|
|
49
|
+
regionSelectFieldApi.exists() &&
|
|
50
|
+
regionSelectFieldApi.setValue();
|
|
44
51
|
} else {
|
|
45
52
|
hasInitialized.current = true;
|
|
46
53
|
}
|
|
47
54
|
}
|
|
48
|
-
}, [country, regionInputFieldApi, regionSelectFieldApi]);
|
|
49
|
-
|
|
50
|
-
const { data, loading } = useQuery(getRegionsQuery, {
|
|
51
|
-
variables: { countryCode: country },
|
|
52
|
-
skip: !country
|
|
53
|
-
});
|
|
55
|
+
}, [country, regionInputFieldApi, regionSelectFieldApi, loading]);
|
|
54
56
|
|
|
55
57
|
let formattedRegionsData = [{ label: 'Loading Regions...', value: '' }];
|
|
56
58
|
if (data) {
|
|
@@ -14,9 +14,9 @@ export const ProductsFragment = gql`
|
|
|
14
14
|
items {
|
|
15
15
|
id
|
|
16
16
|
name
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
price_range {
|
|
18
|
+
maximum_price {
|
|
19
|
+
regular_price {
|
|
20
20
|
currency
|
|
21
21
|
value
|
|
22
22
|
}
|
|
@@ -26,8 +26,9 @@ export const ProductsFragment = gql`
|
|
|
26
26
|
small_image {
|
|
27
27
|
url
|
|
28
28
|
}
|
|
29
|
+
stock_status
|
|
30
|
+
type_id
|
|
29
31
|
url_key
|
|
30
|
-
url_suffix
|
|
31
32
|
}
|
|
32
33
|
page_info {
|
|
33
34
|
total_pages
|
|
@@ -14,7 +14,10 @@ export const ProductDetailsFragment = gql`
|
|
|
14
14
|
}
|
|
15
15
|
id
|
|
16
16
|
media_gallery_entries {
|
|
17
|
+
# id is deprecated and unused in our code, but lint rules require we
|
|
18
|
+
# request it if available
|
|
17
19
|
id
|
|
20
|
+
uid
|
|
18
21
|
label
|
|
19
22
|
position
|
|
20
23
|
disabled
|
|
@@ -34,6 +37,7 @@ export const ProductDetailsFragment = gql`
|
|
|
34
37
|
small_image {
|
|
35
38
|
url
|
|
36
39
|
}
|
|
40
|
+
stock_status
|
|
37
41
|
url_key
|
|
38
42
|
... on ConfigurableProduct {
|
|
39
43
|
configurable_options {
|
|
@@ -64,7 +68,10 @@ export const ProductDetailsFragment = gql`
|
|
|
64
68
|
product {
|
|
65
69
|
id
|
|
66
70
|
media_gallery_entries {
|
|
71
|
+
# id is deprecated and unused in our code, but lint rules require we
|
|
72
|
+
# request it if available
|
|
67
73
|
id
|
|
74
|
+
uid
|
|
68
75
|
disabled
|
|
69
76
|
file
|
|
70
77
|
label
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
-
import { useHistory } from 'react-router-dom';
|
|
3
|
-
|
|
4
2
|
import { useQuery } from '@apollo/client';
|
|
5
3
|
|
|
6
4
|
import { useAppContext } from '@magento/peregrine/lib/context/app';
|
|
7
5
|
import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
8
|
-
|
|
9
6
|
import mergeOperations from '@magento/peregrine/lib/util/shallowMerge';
|
|
7
|
+
|
|
10
8
|
import defaultOperations from './savedPaymentsPage.gql';
|
|
11
9
|
|
|
12
10
|
export const normalizeTokens = responseData => {
|
|
@@ -46,7 +44,6 @@ export const useSavedPaymentsPage = (props = {}) => {
|
|
|
46
44
|
actions: { setPageLoading }
|
|
47
45
|
}
|
|
48
46
|
] = useAppContext();
|
|
49
|
-
const history = useHistory();
|
|
50
47
|
const [{ isSignedIn }] = useUserContext();
|
|
51
48
|
|
|
52
49
|
const { data: savedPaymentsData, loading } = useQuery(
|
|
@@ -58,13 +55,6 @@ export const useSavedPaymentsPage = (props = {}) => {
|
|
|
58
55
|
}
|
|
59
56
|
);
|
|
60
57
|
|
|
61
|
-
// If the user is no longer signed in, redirect to the home page.
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
if (!isSignedIn) {
|
|
64
|
-
history.push('/');
|
|
65
|
-
}
|
|
66
|
-
}, [history, isSignedIn]);
|
|
67
|
-
|
|
68
58
|
// Update the page indicator if the GraphQL query is in flight.
|
|
69
59
|
useEffect(() => {
|
|
70
60
|
setPageLoading(loading);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect, useMemo } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import useFieldState from '@magento/peregrine/lib/hooks/hook-wrappers/useInformedFieldStateWrapper';
|
|
3
3
|
import { useLazyQuery } from '@apollo/client';
|
|
4
4
|
import debounce from 'lodash.debounce';
|
|
5
5
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useFormApi } from 'informed';
|
|
3
|
+
import useFieldState from '@magento/peregrine/lib/hooks/hook-wrappers/useInformedFieldStateWrapper';
|
|
3
4
|
|
|
4
5
|
import { getSearchParam } from '@magento/peregrine/lib/hooks/useSearchParam';
|
|
5
6
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useLocation } from 'react-router-dom';
|
|
3
3
|
|
|
4
4
|
import { DELIMITER } from '../FilterModal/helpers';
|
|
5
|
+
|
|
5
6
|
// TODO: derive from store config when available
|
|
6
7
|
const setSearchParams = (existing, options) => {
|
|
7
8
|
const params = new URLSearchParams(existing);
|
|
@@ -23,13 +24,10 @@ const setSearchParams = (existing, options) => {
|
|
|
23
24
|
*/
|
|
24
25
|
export const useSuggestedCategory = props => {
|
|
25
26
|
const { onNavigate, ...restProps } = props;
|
|
26
|
-
const { createHref } = useHistory();
|
|
27
27
|
const { search } = useLocation();
|
|
28
|
+
|
|
28
29
|
const nextSearchParams = setSearchParams(search, restProps);
|
|
29
|
-
const destination =
|
|
30
|
-
pathname: '/search.html',
|
|
31
|
-
search: nextSearchParams
|
|
32
|
-
});
|
|
30
|
+
const destination = `/search.html?${nextSearchParams}`;
|
|
33
31
|
|
|
34
32
|
const handleClick = useCallback(() => {
|
|
35
33
|
if (typeof onNavigate === 'function') {
|
|
@@ -43,20 +43,21 @@ export const PRODUCT_SEARCH = gql`
|
|
|
43
43
|
items {
|
|
44
44
|
id
|
|
45
45
|
name
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
url_key
|
|
50
|
-
url_suffix
|
|
51
|
-
price {
|
|
52
|
-
regularPrice {
|
|
53
|
-
amount {
|
|
54
|
-
value
|
|
46
|
+
price_range {
|
|
47
|
+
maximum_price {
|
|
48
|
+
regular_price {
|
|
55
49
|
currency
|
|
50
|
+
value
|
|
56
51
|
}
|
|
57
52
|
}
|
|
58
53
|
}
|
|
59
54
|
sku
|
|
55
|
+
small_image {
|
|
56
|
+
url
|
|
57
|
+
}
|
|
58
|
+
stock_status
|
|
59
|
+
type_id
|
|
60
|
+
url_key
|
|
60
61
|
}
|
|
61
62
|
page_info {
|
|
62
63
|
total_pages
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { gql } from '@apollo/client';
|
|
2
|
+
import { CheckoutPageFragment } from '../CheckoutPage/checkoutPageFragments.gql';
|
|
2
3
|
|
|
3
4
|
export const GET_CUSTOMER = gql`
|
|
4
5
|
query GetCustomerAfterSignIn {
|
|
@@ -39,8 +40,10 @@ export const MERGE_CARTS = gql`
|
|
|
39
40
|
items {
|
|
40
41
|
id
|
|
41
42
|
}
|
|
43
|
+
...CheckoutPageFragment
|
|
42
44
|
}
|
|
43
45
|
}
|
|
46
|
+
${CheckoutPageFragment}
|
|
44
47
|
`;
|
|
45
48
|
|
|
46
49
|
export default {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo } from 'react';
|
|
2
|
+
import { useHistory } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import { useUserContext } from '@magento/peregrine/lib/context/user';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {function} useSignInPage
|
|
8
|
+
*
|
|
9
|
+
* @param {String} props.createAccountPageUrl - Create Account Password Page url
|
|
10
|
+
* @param {String} props.forgotPasswordPageUrl - Forgot Password Page url
|
|
11
|
+
* @param {String} props.signedInRedirectUrl - Url to push when user is signed in
|
|
12
|
+
*
|
|
13
|
+
* @returns {{
|
|
14
|
+
* signInProps: object
|
|
15
|
+
* }}
|
|
16
|
+
*/
|
|
17
|
+
export const useSignInPage = props => {
|
|
18
|
+
const {
|
|
19
|
+
createAccountPageUrl,
|
|
20
|
+
forgotPasswordPageUrl,
|
|
21
|
+
signedInRedirectUrl
|
|
22
|
+
} = props;
|
|
23
|
+
const history = useHistory();
|
|
24
|
+
const [{ isSignedIn }] = useUserContext();
|
|
25
|
+
|
|
26
|
+
// Keep location state in memory when pushing history and redirect to
|
|
27
|
+
// the `from` url instead when signing in
|
|
28
|
+
const historyState = useMemo(() => {
|
|
29
|
+
return history && history.location.state ? history.location.state : {};
|
|
30
|
+
}, [history]);
|
|
31
|
+
const fromRedirectUrl = historyState.from || null;
|
|
32
|
+
|
|
33
|
+
// Redirect if user is signed in
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (isSignedIn) {
|
|
36
|
+
if (fromRedirectUrl || signedInRedirectUrl) {
|
|
37
|
+
history.push(fromRedirectUrl || signedInRedirectUrl);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, [history, isSignedIn, fromRedirectUrl, signedInRedirectUrl]);
|
|
41
|
+
|
|
42
|
+
const handleShowCreateAccount = useCallback(() => {
|
|
43
|
+
if (createAccountPageUrl) {
|
|
44
|
+
history.push(createAccountPageUrl, historyState);
|
|
45
|
+
}
|
|
46
|
+
}, [createAccountPageUrl, history, historyState]);
|
|
47
|
+
|
|
48
|
+
const handleShowForgotPassword = useCallback(() => {
|
|
49
|
+
if (forgotPasswordPageUrl) {
|
|
50
|
+
history.push(forgotPasswordPageUrl, historyState);
|
|
51
|
+
}
|
|
52
|
+
}, [forgotPasswordPageUrl, history, historyState]);
|
|
53
|
+
|
|
54
|
+
const signInProps = {
|
|
55
|
+
classes: { modal_active: undefined },
|
|
56
|
+
showCreateAccount: handleShowCreateAccount,
|
|
57
|
+
showForgotPassword: handleShowForgotPassword
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
signInProps
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -132,8 +132,8 @@ export const useSingleWishlist = props => {
|
|
|
132
132
|
id: 'wishlistButton.addText',
|
|
133
133
|
defaultMessage: 'Add to Favorites'
|
|
134
134
|
}),
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
isDisabled: isSelected,
|
|
136
|
+
onPress: handleClick,
|
|
137
137
|
type: 'button'
|
|
138
138
|
}),
|
|
139
139
|
[formatMessage, handleClick, isSelected]
|
|
@@ -23,7 +23,8 @@ export const useAddToListButton = props => {
|
|
|
23
23
|
if (storeConfig.enable_multiple_wishlists === '1' && isSignedIn) {
|
|
24
24
|
return {
|
|
25
25
|
...singleButtonProps,
|
|
26
|
-
|
|
26
|
+
'aria-haspopup': 'dialog',
|
|
27
|
+
onPress: () => {
|
|
27
28
|
setIsModalOpen(true);
|
|
28
29
|
|
|
29
30
|
if (beforeAdd) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { useCallback, useState } from 'react';
|
|
2
|
-
import { useMutation } from '@apollo/client';
|
|
1
|
+
import { useCallback, useState, useMemo } from 'react';
|
|
2
|
+
import { useMutation, useQuery } from '@apollo/client';
|
|
3
3
|
import DEFAULT_OPERATIONS from './wishlist.gql';
|
|
4
|
+
import getWishlistConfigQuery from './wishlistConfig.gql';
|
|
4
5
|
import mergeOperations from '../../util/shallowMerge';
|
|
5
6
|
|
|
6
7
|
const dialogs = {
|
|
@@ -20,15 +21,21 @@ const dialogs = {
|
|
|
20
21
|
*/
|
|
21
22
|
export const useActionMenu = (props = {}) => {
|
|
22
23
|
const { id } = props;
|
|
23
|
-
const operations = mergeOperations(
|
|
24
|
+
const operations = mergeOperations(
|
|
25
|
+
DEFAULT_OPERATIONS,
|
|
26
|
+
getWishlistConfigQuery,
|
|
27
|
+
props.operations
|
|
28
|
+
);
|
|
24
29
|
const { getCustomerWishlistQuery, updateWishlistMutation } = operations;
|
|
25
30
|
const [currentDialog, setCurrentDialog] = useState(dialogs.NONE);
|
|
31
|
+
const [displayError, setDisplayError] = useState(false);
|
|
26
32
|
|
|
27
33
|
const handleActionMenuClick = useCallback(() => {
|
|
28
34
|
setCurrentDialog(dialogs.LIST_ACTIONS);
|
|
29
35
|
}, []);
|
|
30
36
|
|
|
31
37
|
const handleHideDialogs = useCallback(() => {
|
|
38
|
+
setDisplayError(false);
|
|
32
39
|
setCurrentDialog(dialogs.NONE);
|
|
33
40
|
}, []);
|
|
34
41
|
|
|
@@ -44,6 +51,26 @@ export const useActionMenu = (props = {}) => {
|
|
|
44
51
|
{ error: updateWishlistErrors, loading: isEditInProgress }
|
|
45
52
|
] = useMutation(updateWishlistMutation);
|
|
46
53
|
|
|
54
|
+
const { data: storeConfigData } = useQuery(
|
|
55
|
+
operations.getWishlistConfigQuery,
|
|
56
|
+
{
|
|
57
|
+
fetchPolicy: 'cache-and-network',
|
|
58
|
+
nextFetchPolicy: 'cache-first'
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const shouldRender = useMemo(() => {
|
|
63
|
+
let multipleWishlistEnabled = false;
|
|
64
|
+
try {
|
|
65
|
+
if (storeConfigData.storeConfig.enable_multiple_wishlists === '1') {
|
|
66
|
+
multipleWishlistEnabled = true;
|
|
67
|
+
}
|
|
68
|
+
} catch (e) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return storeConfigData && multipleWishlistEnabled;
|
|
72
|
+
}, [storeConfigData]);
|
|
73
|
+
|
|
47
74
|
const handleEditWishlist = useCallback(
|
|
48
75
|
async data => {
|
|
49
76
|
// add private visibility because is required field for ee
|
|
@@ -63,6 +90,7 @@ export const useActionMenu = (props = {}) => {
|
|
|
63
90
|
});
|
|
64
91
|
setCurrentDialog(dialogs.NONE);
|
|
65
92
|
} catch (error) {
|
|
93
|
+
setDisplayError(true);
|
|
66
94
|
if (process.env.NODE_ENV !== 'production') {
|
|
67
95
|
console.error(error);
|
|
68
96
|
}
|
|
@@ -71,15 +99,21 @@ export const useActionMenu = (props = {}) => {
|
|
|
71
99
|
[getCustomerWishlistQuery, id, updateWishlist]
|
|
72
100
|
);
|
|
73
101
|
|
|
102
|
+
const errors = useMemo(
|
|
103
|
+
() => (displayError ? [updateWishlistErrors] : [false]),
|
|
104
|
+
[updateWishlistErrors, displayError]
|
|
105
|
+
);
|
|
106
|
+
|
|
74
107
|
return {
|
|
75
108
|
editFavoritesListIsOpen,
|
|
76
|
-
formErrors:
|
|
109
|
+
formErrors: errors,
|
|
77
110
|
handleActionMenuClick,
|
|
78
111
|
handleEditWishlist,
|
|
79
112
|
handleHideDialogs,
|
|
80
113
|
handleShowEditFavorites,
|
|
81
114
|
isEditInProgress,
|
|
82
|
-
listActionsIsOpen
|
|
115
|
+
listActionsIsOpen,
|
|
116
|
+
shouldRender
|
|
83
117
|
};
|
|
84
118
|
};
|
|
85
119
|
|