@graphcommerce/magento-product 8.1.0-canary.9 → 9.0.0-canary.100
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/Api/ProductListItem.graphql +1 -2
- package/Api/ProductPageItem.graphql +1 -1
- package/CHANGELOG.md +276 -84
- package/Config.graphqls +13 -0
- package/components/AddProductsToCart/AddProductsToCartButton.tsx +17 -4
- package/components/AddProductsToCart/AddProductsToCartFab.tsx +7 -2
- package/components/AddProductsToCart/AddProductsToCartForm.tsx +31 -29
- package/components/AddProductsToCart/AddProductsToCartSnackbar.tsx +14 -63
- package/components/AddProductsToCart/AddProductsToCartSnackbarMessage.tsx +84 -0
- package/components/AddProductsToCart/UseAddProductsToCartAction.graphql +1 -1
- package/components/AddProductsToCart/findAddedItems.ts +1 -4
- package/components/AddProductsToCart/index.ts +1 -0
- package/components/AddProductsToCart/useAddProductsToCartAction.ts +2 -1
- package/components/AddProductsToCart/useFormAddProductsToCart.ts +1 -2
- package/components/JsonLdProduct/JsonLdProduct.graphql +1 -1
- package/components/JsonLdProduct/ProductPageJsonLd.tsx +1 -1
- package/components/ProductAddToCart/ProductAddToCart.tsx +6 -8
- package/components/ProductCustomizable/CustomizableCheckboxOption.tsx +3 -4
- package/components/ProductCustomizable/CustomizableMultipleOption.tsx +2 -2
- package/components/ProductCustomizable/CustomizableRadioOption.tsx +2 -2
- package/components/ProductCustomizable/ProductCustomizable.graphql +1 -1
- package/components/ProductCustomizable/index.ts +1 -0
- package/components/ProductCustomizable/productCustomizableSelectors.ts +59 -0
- package/components/ProductFiltersPro/PriceSlider.tsx +1 -2
- package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +4 -5
- package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +6 -7
- package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +1 -1
- package/components/ProductFiltersPro/ProductFiltersPro.tsx +103 -19
- package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +41 -20
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +6 -10
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersSidebar.tsx +18 -8
- package/components/ProductFiltersPro/ProductFiltersProCategorySection.tsx +130 -0
- package/components/ProductFiltersPro/ProductFiltersProChips.tsx +10 -8
- package/components/ProductFiltersPro/ProductFiltersProClearAll.tsx +4 -16
- package/components/ProductFiltersPro/ProductFiltersProLayoutSidebar.tsx +15 -7
- package/components/ProductFiltersPro/ProductFiltersProLimitChip.tsx +2 -8
- package/components/ProductFiltersPro/ProductFiltersProLimitSection.tsx +7 -10
- package/components/ProductFiltersPro/ProductFiltersProNoResults.tsx +79 -0
- package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +5 -7
- package/components/ProductFiltersPro/ProductFiltersProSortDirectionArrow.tsx +2 -4
- package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +11 -3
- package/components/ProductFiltersPro/activeAggregations.ts +5 -9
- package/components/ProductFiltersPro/applyAggregationCount.ts +14 -8
- package/components/ProductFiltersPro/index.ts +9 -0
- package/components/ProductFiltersPro/{useClearAllFiltersHandler.ts → useProductFiltersProClearAllAction.ts} +1 -1
- package/components/ProductFiltersPro/useProductFiltersProHasFiltersApplied.ts +21 -0
- package/components/ProductFiltersPro/useProductFiltersProSort.tsx +7 -3
- package/components/ProductList/ProductList.graphql +8 -5
- package/components/ProductListCount/ProductListCount.tsx +3 -1
- package/components/ProductListFilters/ProductFilters.graphql +11 -2
- package/components/ProductListFilters/ProductListFilters.graphql +1 -1
- package/components/ProductListFilters/ProductListFilters.tsx +13 -19
- package/components/ProductListFiltersContainer/ProductListFiltersContainer.tsx +2 -4
- package/components/ProductListItem/ProductDiscountLabel.tsx +2 -3
- package/components/ProductListItem/ProductListItem.tsx +3 -3
- package/components/ProductListItem/ProductListItemTitleAndPrice.tsx +18 -15
- package/components/ProductListItems/ProductFilterTypes.graphql +8 -0
- package/components/ProductListItems/ProductListItemsBase.tsx +71 -30
- package/components/ProductListItems/filterTypes.tsx +14 -7
- package/components/ProductListItems/filteredProductList.tsx +44 -17
- package/components/ProductListItems/getFilterTypes.ts +33 -4
- package/components/ProductListItems/productListApplyCategoryDefaults.ts +50 -4
- package/components/ProductListItems/renderer.tsx +8 -2
- package/components/ProductListPagination/ProductListPagination.tsx +39 -20
- package/components/ProductListPrice/ProductListPrice.tsx +9 -4
- package/components/ProductListSuggestions/ProductListSuggestions.graphql +5 -0
- package/components/ProductListSuggestions/ProductListSuggestions.tsx +42 -0
- package/components/ProductPageBreadcrumb/ProductPageBreadcrumb.graphql +3 -0
- package/components/ProductPageBreadcrumb/ProductPageBreadcrumb.tsx +3 -0
- package/components/ProductPageBreadcrumb/ProductPageBreadcrumbs.tsx +40 -0
- package/components/ProductPageBreadcrumb/index.ts +1 -0
- package/components/ProductPageDescription/ComplexTextValue.graphql +1 -1
- package/components/ProductPageDescription/ProductPageDescription.tsx +1 -1
- package/components/ProductPageGallery/ProductImage.graphql +1 -0
- package/components/ProductPageGallery/ProductPageGallery.tsx +14 -8
- package/components/ProductPagePrice/ProductPagePrice.graphql +0 -6
- package/components/ProductPagePrice/ProductPagePrice.tsx +19 -12
- package/components/ProductPagePrice/ProductPagePriceTiers.tsx +4 -3
- package/components/ProductPagePrice/useCustomizableOptionPrice.ts +11 -53
- package/components/ProductShortDescription/ProductShortDescription.tsx +2 -0
- package/components/ProductSpecs/ProductSpecs.graphql +21 -1
- package/components/ProductSpecs/ProductSpecs.tsx +5 -11
- package/components/ProductSpecs/ProductSpecsAggregations.tsx +34 -0
- package/components/ProductSpecs/ProductSpecsCustomAttributes.tsx +45 -0
- package/components/ProductSpecs/ProductSpecsTypes.graphql +8 -0
- package/components/ProductStaticPaths/getProductStaticPaths.ts +1 -1
- package/components/ProductWeight/ProductWeight.tsx +12 -9
- package/components/index.ts +2 -0
- package/hooks/useProductList.ts +148 -0
- package/hooks/useProductListLink.ts +6 -3
- package/index.ts +1 -0
- package/package.json +14 -14
@@ -1,5 +1,6 @@
|
|
1
|
+
import { useCartEnabled } from '@graphcommerce/magento-cart'
|
1
2
|
import { Fab, FabProps, iconShoppingBag, iconCheckmark } from '@graphcommerce/next-ui'
|
2
|
-
import {
|
3
|
+
import { t } from '@lingui/macro'
|
3
4
|
import { SxProps, Theme } from '@mui/material'
|
4
5
|
import {
|
5
6
|
useAddProductsToCartAction,
|
@@ -16,13 +17,17 @@ export function AddProductsToCartFab(props: AddProductsToCartFabProps) {
|
|
16
17
|
const { icon = iconShoppingBag, product, sku, ...rest } = props
|
17
18
|
const { showSuccess, ...action } = useAddProductsToCartAction(props)
|
18
19
|
|
20
|
+
const cartEnabled = useCartEnabled()
|
21
|
+
|
22
|
+
if (!cartEnabled) return null
|
23
|
+
|
19
24
|
return (
|
20
25
|
<Fab
|
21
26
|
type='submit'
|
22
27
|
{...rest}
|
23
28
|
{...action}
|
24
29
|
icon={showSuccess && !action.loading ? iconCheckmark : icon}
|
25
|
-
aria-label={
|
30
|
+
aria-label={t`Add to Cart`}
|
26
31
|
/>
|
27
32
|
)
|
28
33
|
}
|
@@ -5,8 +5,8 @@ import {
|
|
5
5
|
CrosssellsDocument,
|
6
6
|
CrosssellsQuery,
|
7
7
|
} from '@graphcommerce/magento-cart'
|
8
|
-
import {
|
9
|
-
import { Box, SxProps, Theme
|
8
|
+
import { ErrorSnackbarProps, MessageSnackbarProps, nonNullable } from '@graphcommerce/next-ui'
|
9
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
10
10
|
import { useRouter } from 'next/router'
|
11
11
|
import { useMemo, useRef } from 'react'
|
12
12
|
import { AddProductsToCartDocument, AddProductsToCartMutation } from './AddProductsToCart.gql'
|
@@ -22,30 +22,27 @@ import {
|
|
22
22
|
} from './useFormAddProductsToCart'
|
23
23
|
|
24
24
|
export type AddProductsToCartFormProps = {
|
25
|
-
// The props are actually used, but are passed through useThemeProps and that breaks react/no-unused-prop-types
|
26
|
-
// eslint-disable-next-line react/no-unused-prop-types
|
27
25
|
children: React.ReactNode
|
28
|
-
// eslint-disable-next-line react/no-unused-prop-types
|
29
26
|
sx?: SxProps<Theme>
|
30
|
-
// eslint-disable-next-line react/no-unused-prop-types
|
31
27
|
redirect?: RedirectType
|
32
|
-
|
28
|
+
snackbarProps?: AddProductsToCartSnackbarProps
|
29
|
+
|
30
|
+
/**
|
31
|
+
* @deprecated use snackbarProps.errorSnackbar instead
|
32
|
+
*/
|
33
|
+
errorSnackbar?: Omit<ErrorSnackbarProps, 'open'>
|
34
|
+
/**
|
35
|
+
* @deprecated use snackbarProps.successSnackbar instead
|
36
|
+
*/
|
37
|
+
successSnackbar?: Omit<MessageSnackbarProps, 'open' | 'action'>
|
38
|
+
/**
|
39
|
+
* @deprecated use snackbarProps.disableSuccessSnackbar instead
|
40
|
+
*/
|
33
41
|
disableSuccessSnackbar?: boolean
|
34
|
-
} & UseFormGraphQlOptions<AddProductsToCartMutation, AddProductsToCartFields>
|
35
|
-
AddProductsToCartSnackbarProps
|
42
|
+
} & UseFormGraphQlOptions<AddProductsToCartMutation, AddProductsToCartFields>
|
36
43
|
|
37
44
|
const name = 'AddProductsToCartForm'
|
38
45
|
|
39
|
-
/** Expose the component to be exendable in your theme.components */
|
40
|
-
declare module '@mui/material/styles/components' {
|
41
|
-
interface Components {
|
42
|
-
AddProductsToCartForm?: Pick<
|
43
|
-
ExtendableComponent<Omit<AddProductsToCartFormProps, 'children'>>,
|
44
|
-
'defaultProps'
|
45
|
-
>
|
46
|
-
}
|
47
|
-
}
|
48
|
-
|
49
46
|
/**
|
50
47
|
* Component that handles adding products to the cart. Used on the product page, but can be used for
|
51
48
|
* any product listing.
|
@@ -66,8 +63,9 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
66
63
|
disableSuccessSnackbar,
|
67
64
|
errorSnackbar,
|
68
65
|
successSnackbar,
|
66
|
+
snackbarProps,
|
69
67
|
...formProps
|
70
|
-
} =
|
68
|
+
} = props
|
71
69
|
const router = useRouter()
|
72
70
|
const client = useApolloClient()
|
73
71
|
const crosssellsQuery = useRef<Promise<ApolloQueryResult<CrosssellsQuery>>>()
|
@@ -79,7 +77,6 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
79
77
|
AddProductsToCartDocument,
|
80
78
|
{
|
81
79
|
...formProps,
|
82
|
-
experimental_useV2: true,
|
83
80
|
// We're stripping out incomplete entered options.
|
84
81
|
onBeforeSubmit: async (variables) => {
|
85
82
|
const variables2 = (await formProps.onBeforeSubmit?.(variables)) ?? variables
|
@@ -90,7 +87,7 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
90
87
|
const requestData = {
|
91
88
|
cartId,
|
92
89
|
cartItems: cartItems
|
93
|
-
.filter((cartItem) => cartItem.sku)
|
90
|
+
.filter((cartItem) => cartItem.sku && cartItem.quantity !== 0)
|
94
91
|
.map(({ customizable_options, ...cartItem }) => {
|
95
92
|
const options = Object.values(customizable_options ?? {})
|
96
93
|
.flat(1)
|
@@ -103,7 +100,12 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
103
100
|
...(cartItem.selected_options ?? []).filter(Boolean),
|
104
101
|
...options,
|
105
102
|
],
|
106
|
-
entered_options:
|
103
|
+
entered_options: [
|
104
|
+
...(cartItem.entered_options
|
105
|
+
?.filter((option) => option?.value)
|
106
|
+
.filter(nonNullable)
|
107
|
+
.map((option) => ({ uid: option.uid, value: `${option?.value}` })) ?? []),
|
108
|
+
],
|
107
109
|
}
|
108
110
|
}),
|
109
111
|
}
|
@@ -155,12 +157,12 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
155
157
|
<Box component='form' onSubmit={submit} noValidate sx={sx} className={name}>
|
156
158
|
{children}
|
157
159
|
</Box>
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
160
|
+
<AddProductsToCartSnackbar
|
161
|
+
errorSnackbar={errorSnackbar}
|
162
|
+
successSnackbar={successSnackbar}
|
163
|
+
disableSuccessSnackbar={disableSuccessSnackbar}
|
164
|
+
{...snackbarProps}
|
165
|
+
/>
|
164
166
|
</AddProductsToCartContext.Provider>
|
165
167
|
)
|
166
168
|
}
|
@@ -1,18 +1,7 @@
|
|
1
1
|
import { useFormState } from '@graphcommerce/ecommerce-ui'
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
Button,
|
5
|
-
ErrorSnackbar,
|
6
|
-
ErrorSnackbarProps,
|
7
|
-
iconChevronRight,
|
8
|
-
IconSvg,
|
9
|
-
MessageSnackbar,
|
10
|
-
MessageSnackbarProps,
|
11
|
-
nonNullable,
|
12
|
-
useLocale,
|
13
|
-
} from '@graphcommerce/next-ui'
|
14
|
-
import { Trans } from '@lingui/react'
|
2
|
+
import { ErrorSnackbarProps, MessageSnackbarProps, nonNullable } from '@graphcommerce/next-ui'
|
15
3
|
import { useMemo } from 'react'
|
4
|
+
import { AddProductsToCartSnackbarMessage } from './AddProductsToCartSnackbarMessage'
|
16
5
|
import { findAddedItems } from './findAddedItems'
|
17
6
|
import { toUserErrors } from './toUserErrors'
|
18
7
|
import { useFormAddProductsToCart } from './useFormAddProductsToCart'
|
@@ -20,18 +9,19 @@ import { useFormAddProductsToCart } from './useFormAddProductsToCart'
|
|
20
9
|
export type AddProductsToCartSnackbarProps = {
|
21
10
|
errorSnackbar?: Omit<ErrorSnackbarProps, 'open'>
|
22
11
|
successSnackbar?: Omit<MessageSnackbarProps, 'open' | 'action'>
|
12
|
+
disableSuccessSnackbar?: boolean
|
23
13
|
}
|
24
14
|
|
25
15
|
export function AddProductsToCartSnackbar(props: AddProductsToCartSnackbarProps) {
|
26
|
-
const { errorSnackbar, successSnackbar } = props
|
16
|
+
const { errorSnackbar, successSnackbar, disableSuccessSnackbar } = props
|
27
17
|
const { error, data, redirect, control, submittedVariables } = useFormAddProductsToCart()
|
28
|
-
const formState = useFormState({ control })
|
29
18
|
|
30
|
-
const
|
19
|
+
const formState = useFormState({ control })
|
31
20
|
|
32
21
|
const userErrors = toUserErrors(data)
|
33
22
|
|
34
23
|
const showSuccess =
|
24
|
+
!disableSuccessSnackbar &&
|
35
25
|
!formState.isSubmitting &&
|
36
26
|
formState.isSubmitSuccessful &&
|
37
27
|
!error?.message &&
|
@@ -43,53 +33,14 @@ export function AddProductsToCartSnackbar(props: AddProductsToCartSnackbarProps)
|
|
43
33
|
[data, submittedVariables],
|
44
34
|
)
|
45
35
|
|
46
|
-
const showErrorSnackbar = userErrors.length > 0
|
47
|
-
|
48
36
|
return (
|
49
|
-
|
50
|
-
{
|
51
|
-
|
52
|
-
{
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
{showSuccess && (
|
59
|
-
<MessageSnackbar
|
60
|
-
variant='pill'
|
61
|
-
severity='success'
|
62
|
-
{...successSnackbar}
|
63
|
-
open={showSuccess}
|
64
|
-
action={
|
65
|
-
<Button
|
66
|
-
href='/cart'
|
67
|
-
id='view-shopping-cart-button'
|
68
|
-
size='medium'
|
69
|
-
variant='pill'
|
70
|
-
color='secondary'
|
71
|
-
endIcon={<IconSvg src={iconChevronRight} />}
|
72
|
-
sx={{ display: 'flex' }}
|
73
|
-
>
|
74
|
-
<Trans id='View shopping cart' />
|
75
|
-
</Button>
|
76
|
-
}
|
77
|
-
>
|
78
|
-
<Trans
|
79
|
-
id={
|
80
|
-
addedItems.length === 1
|
81
|
-
? '<0>{name}</0> has been added to your shopping cart!'
|
82
|
-
: '<0>{name}</0> have been added to your shopping cart!'
|
83
|
-
}
|
84
|
-
components={{ 0: <strong /> }}
|
85
|
-
values={{
|
86
|
-
name: formatter.format(
|
87
|
-
addedItems.map((item) => item?.itemInCart?.product.name).filter(nonNullable),
|
88
|
-
),
|
89
|
-
}}
|
90
|
-
/>
|
91
|
-
</MessageSnackbar>
|
92
|
-
)}
|
93
|
-
</>
|
37
|
+
<AddProductsToCartSnackbarMessage
|
38
|
+
error={!formState.isSubmitting ? error : undefined}
|
39
|
+
showSuccess={showSuccess}
|
40
|
+
userErrors={data?.addProductsToCart?.user_errors.filter(nonNullable)}
|
41
|
+
addedItems={addedItems.map((item) => item.itemInCart?.product.name).filter(nonNullable)}
|
42
|
+
errorSnackbar={errorSnackbar}
|
43
|
+
successSnackbar={successSnackbar}
|
44
|
+
/>
|
94
45
|
)
|
95
46
|
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { ApolloError } from '@graphcommerce/graphql'
|
2
|
+
import { CartUserInputError } from '@graphcommerce/graphql-mesh'
|
3
|
+
import { ApolloCartErrorSnackbar } from '@graphcommerce/magento-cart'
|
4
|
+
import {
|
5
|
+
Button,
|
6
|
+
ErrorSnackbar,
|
7
|
+
ErrorSnackbarProps,
|
8
|
+
IconSvg,
|
9
|
+
ListFormat,
|
10
|
+
MessageSnackbar,
|
11
|
+
MessageSnackbarProps,
|
12
|
+
iconChevronRight,
|
13
|
+
} from '@graphcommerce/next-ui'
|
14
|
+
import { Plural, Trans } from '@lingui/macro'
|
15
|
+
|
16
|
+
export type AddProductsToCartSnackbarMessageProps = {
|
17
|
+
errorSnackbar?: Omit<ErrorSnackbarProps, 'open'>
|
18
|
+
successSnackbar?: Omit<MessageSnackbarProps, 'open' | 'action'>
|
19
|
+
error?: ApolloError
|
20
|
+
userErrors?: Pick<CartUserInputError, 'message'>[]
|
21
|
+
showSuccess: boolean
|
22
|
+
addedItems: string[]
|
23
|
+
}
|
24
|
+
|
25
|
+
export function AddProductsToCartSnackbarMessage(props: AddProductsToCartSnackbarMessageProps) {
|
26
|
+
const { errorSnackbar, successSnackbar, error, userErrors, showSuccess, addedItems } = props
|
27
|
+
|
28
|
+
const showErrorSnackbar = !!userErrors?.length
|
29
|
+
|
30
|
+
return (
|
31
|
+
<>
|
32
|
+
{error && <ApolloCartErrorSnackbar error={error} />}
|
33
|
+
|
34
|
+
{showErrorSnackbar && (
|
35
|
+
<ErrorSnackbar variant='pill' severity='error' {...errorSnackbar} open={showErrorSnackbar}>
|
36
|
+
<>{userErrors.map((e) => e?.message).join(', ')}</>
|
37
|
+
</ErrorSnackbar>
|
38
|
+
)}
|
39
|
+
|
40
|
+
{showSuccess && (
|
41
|
+
<MessageSnackbar
|
42
|
+
variant='pill'
|
43
|
+
severity='success'
|
44
|
+
{...successSnackbar}
|
45
|
+
open={showSuccess}
|
46
|
+
action={
|
47
|
+
<Button
|
48
|
+
href='/cart'
|
49
|
+
id='view-shopping-cart-button'
|
50
|
+
size='medium'
|
51
|
+
variant='pill'
|
52
|
+
color='secondary'
|
53
|
+
endIcon={<IconSvg src={iconChevronRight} />}
|
54
|
+
sx={{ display: 'flex' }}
|
55
|
+
>
|
56
|
+
<Trans>View shopping cart</Trans>
|
57
|
+
</Button>
|
58
|
+
}
|
59
|
+
>
|
60
|
+
<Plural
|
61
|
+
value={addedItems.length}
|
62
|
+
one={
|
63
|
+
<Trans>
|
64
|
+
<ListFormat listStyle='long' type='conjunction'>
|
65
|
+
{addedItems.map((item) => item)}
|
66
|
+
</ListFormat>{' '}
|
67
|
+
has been added to your shopping cart
|
68
|
+
</Trans>
|
69
|
+
}
|
70
|
+
two={
|
71
|
+
<Trans>
|
72
|
+
<ListFormat listStyle='long' type='conjunction'>
|
73
|
+
{addedItems.map((item) => item)}
|
74
|
+
</ListFormat>{' '}
|
75
|
+
have been added to your shopping cart!
|
76
|
+
</Trans>
|
77
|
+
}
|
78
|
+
other={<Trans># products have been added to your shopping cart!</Trans>}
|
79
|
+
/>
|
80
|
+
</MessageSnackbar>
|
81
|
+
)}
|
82
|
+
</>
|
83
|
+
)
|
84
|
+
}
|
@@ -47,10 +47,7 @@ export function findAddedItems(
|
|
47
47
|
}
|
48
48
|
}
|
49
49
|
|
50
|
-
const customizable_options =
|
51
|
-
? cartItem.configurable_customizable
|
52
|
-
: cartItem.customizable_options
|
53
|
-
|
50
|
+
const { customizable_options } = cartItem
|
54
51
|
const matchEntered = filterNonNullableKeys(itemVariable.entered_options).every(
|
55
52
|
(requestOption) =>
|
56
53
|
customizable_options.find(
|
@@ -4,6 +4,7 @@ export * from './AddProductsToCartError'
|
|
4
4
|
export * from './AddProductsToCartFab'
|
5
5
|
export * from './AddProductsToCartForm'
|
6
6
|
export * from './AddProductsToCartSnackbar'
|
7
|
+
export * from './AddProductsToCartSnackbarMessage'
|
7
8
|
export * from './AddProductsToCartQuantity'
|
8
9
|
export * from './useAddProductsToCartAction'
|
9
10
|
export * from './useFormAddProductsToCart'
|
@@ -68,7 +68,8 @@ export function useAddProductsToCartAction(
|
|
68
68
|
if (process.env.NODE_ENV !== 'production') {
|
69
69
|
if (!sku) console.warn(`You must provide a 'sku' to useAddProductsToCartAction`)
|
70
70
|
}
|
71
|
-
|
71
|
+
// TODO should be removed, setting the form value on submission isn't a great idea.
|
72
|
+
if (!getValues(`cartItems.${index}.sku`)) setValue(`cartItems.${index}.sku`, sku ?? '')
|
72
73
|
startTransition(() => {
|
73
74
|
onClickIncoming?.(e)
|
74
75
|
})
|
@@ -1,11 +1,10 @@
|
|
1
1
|
import { UseFormGqlMutationReturn } from '@graphcommerce/ecommerce-ui'
|
2
2
|
import { createContext, useContext } from 'react'
|
3
|
-
import type { LiteralUnion } from 'type-fest'
|
3
|
+
import type { Simplify, LiteralUnion } from 'type-fest'
|
4
4
|
import {
|
5
5
|
AddProductsToCartMutation,
|
6
6
|
AddProductsToCartMutationVariables,
|
7
7
|
} from './AddProductsToCart.gql'
|
8
|
-
import { Simplify } from 'type-fest'
|
9
8
|
|
10
9
|
export type RedirectType = LiteralUnion<'added' | undefined | false, `/${string}`>
|
11
10
|
|
@@ -13,5 +13,5 @@ export function ProductPageJsonLd<T extends { '@type': string }, P extends JsonL
|
|
13
13
|
props: ProductPageJsonLdProps<T, P>,
|
14
14
|
) {
|
15
15
|
const { product, render } = props
|
16
|
-
return <JsonLd<T> item={render(product)} />
|
16
|
+
return <JsonLd<T> item={render(product)} keyVal='product-jsonld' />
|
17
17
|
}
|
@@ -9,7 +9,7 @@ import {
|
|
9
9
|
IconSvg,
|
10
10
|
extendableComponent,
|
11
11
|
} from '@graphcommerce/next-ui'
|
12
|
-
import { Trans } from '@lingui/
|
12
|
+
import { Trans } from '@lingui/macro'
|
13
13
|
import { Divider, Typography, ButtonProps, Box, Alert } from '@mui/material'
|
14
14
|
import React from 'react'
|
15
15
|
import { ProductAddToCartDocument, ProductAddToCartMutationVariables } from './ProductAddToCart.gql'
|
@@ -93,7 +93,7 @@ export function ProductAddToCart(
|
|
93
93
|
})}
|
94
94
|
{...buttonProps}
|
95
95
|
>
|
96
|
-
<Trans
|
96
|
+
<Trans>Add to Cart</Trans>
|
97
97
|
</Button>
|
98
98
|
{additionalButtons}
|
99
99
|
</Box>
|
@@ -125,15 +125,13 @@ export function ProductAddToCart(
|
|
125
125
|
color='secondary'
|
126
126
|
endIcon={<IconSvg src={iconChevronRight} />}
|
127
127
|
>
|
128
|
-
<Trans
|
128
|
+
<Trans>View shopping cart</Trans>
|
129
129
|
</Button>
|
130
130
|
}
|
131
131
|
>
|
132
|
-
<Trans
|
133
|
-
|
134
|
-
|
135
|
-
values={{ name }}
|
136
|
-
/>
|
132
|
+
<Trans>
|
133
|
+
<strong>{name}</strong> has been added to your shopping cart!
|
134
|
+
</Trans>
|
137
135
|
</MessageSnackbar>
|
138
136
|
</Box>
|
139
137
|
)
|
@@ -1,14 +1,13 @@
|
|
1
|
+
import { ActionCardListForm } from '@graphcommerce/ecommerce-ui'
|
1
2
|
import { Money } from '@graphcommerce/magento-store'
|
2
3
|
import {
|
3
|
-
ActionCardListForm,
|
4
4
|
ActionCard,
|
5
|
-
filterNonNullableKeys,
|
6
5
|
ActionCardProps,
|
6
|
+
filterNonNullableKeys,
|
7
7
|
SectionHeader,
|
8
8
|
} from '@graphcommerce/next-ui'
|
9
9
|
import { i18n } from '@lingui/core'
|
10
|
-
|
11
|
-
import { Checkbox, Box } from '@mui/material'
|
10
|
+
import { Box, Checkbox } from '@mui/material'
|
12
11
|
import { useFormAddProductsToCart } from '../AddProductsToCart'
|
13
12
|
import { OptionTypeRenderer } from './CustomizableAreaOption'
|
14
13
|
|
@@ -1,9 +1,9 @@
|
|
1
|
+
import { ActionCardListForm } from '@graphcommerce/ecommerce-ui'
|
1
2
|
import { Money } from '@graphcommerce/magento-store'
|
2
3
|
import {
|
3
|
-
ActionCardListForm,
|
4
4
|
ActionCard,
|
5
|
-
filterNonNullableKeys,
|
6
5
|
ActionCardProps,
|
6
|
+
filterNonNullableKeys,
|
7
7
|
SectionHeader,
|
8
8
|
} from '@graphcommerce/next-ui'
|
9
9
|
import { i18n } from '@lingui/core'
|
@@ -1,9 +1,9 @@
|
|
1
|
+
import { ActionCardListForm } from '@graphcommerce/ecommerce-ui'
|
1
2
|
import { Money } from '@graphcommerce/magento-store'
|
2
3
|
import {
|
3
|
-
ActionCardListForm,
|
4
4
|
ActionCard,
|
5
|
-
filterNonNullableKeys,
|
6
5
|
ActionCardProps,
|
6
|
+
filterNonNullableKeys,
|
7
7
|
SectionHeader,
|
8
8
|
} from '@graphcommerce/next-ui'
|
9
9
|
import { i18n } from '@lingui/core'
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import type { PriceTypeEnum } from '@graphcommerce/graphql-mesh'
|
2
|
+
import type { Simplify } from 'type-fest'
|
3
|
+
import type { CustomizableAreaOptionFragment } from './CustomizableAreaOption.gql'
|
4
|
+
import type { CustomizableCheckboxOptionFragment } from './CustomizableCheckboxOption.gql'
|
5
|
+
import type { CustomizableDateOptionFragment } from './CustomizableDateOption.gql'
|
6
|
+
import type { CustomizableDropDownOptionFragment } from './CustomizableDropDownOption.gql'
|
7
|
+
import type { CustomizableFieldOptionFragment } from './CustomizableFieldOption.gql'
|
8
|
+
import type { CustomizableFileOptionFragment } from './CustomizableFileOption.gql'
|
9
|
+
import type { CustomizableMultipleOptionFragment } from './CustomizableMultipleOption.gql'
|
10
|
+
import type { CustomizableRadioOptionFragment } from './CustomizableRadioOption.gql'
|
11
|
+
import type { ProductCustomizable_SimpleProduct_Fragment } from './ProductCustomizable.gql'
|
12
|
+
|
13
|
+
export type CustomizableProductOptionBase =
|
14
|
+
| {
|
15
|
+
price?: number | null | undefined
|
16
|
+
price_type?: PriceTypeEnum | null | undefined
|
17
|
+
uid?: string | null | undefined
|
18
|
+
}
|
19
|
+
| undefined
|
20
|
+
| null
|
21
|
+
|
22
|
+
export type AnyOption = NonNullable<
|
23
|
+
NonNullable<ProductCustomizable_SimpleProduct_Fragment['options']>[number]
|
24
|
+
>
|
25
|
+
|
26
|
+
export type OptionValueSelector = {
|
27
|
+
[T in AnyOption as T['__typename']]: (
|
28
|
+
option: T,
|
29
|
+
) => CustomizableProductOptionBase | CustomizableProductOptionBase[]
|
30
|
+
}
|
31
|
+
|
32
|
+
type MissingOptionValueSelectors = Omit<
|
33
|
+
OptionValueSelector,
|
34
|
+
keyof typeof productCustomizableSelectors
|
35
|
+
>
|
36
|
+
type DefinedOptionValueSelectors = Partial<
|
37
|
+
Pick<OptionValueSelector, keyof typeof productCustomizableSelectors>
|
38
|
+
>
|
39
|
+
|
40
|
+
type Selectors = Simplify<
|
41
|
+
keyof MissingOptionValueSelectors extends never
|
42
|
+
? (MissingOptionValueSelectors & DefinedOptionValueSelectors) | undefined
|
43
|
+
: MissingOptionValueSelectors & DefinedOptionValueSelectors
|
44
|
+
>
|
45
|
+
|
46
|
+
export const productCustomizableSelectors = {
|
47
|
+
CustomizableAreaOption: (o: CustomizableAreaOptionFragment) => o.areaValue,
|
48
|
+
CustomizableCheckboxOption: (o: CustomizableCheckboxOptionFragment) => o.checkboxValue,
|
49
|
+
CustomizableFileOption: (o: CustomizableFileOptionFragment) => o.fileValue,
|
50
|
+
CustomizableDateOption: (o: CustomizableDateOptionFragment) => o.dateValue,
|
51
|
+
CustomizableDropDownOption: (o: CustomizableDropDownOptionFragment) => o.dropdownValue,
|
52
|
+
CustomizableFieldOption: (o: CustomizableFieldOptionFragment) => o.fieldValue,
|
53
|
+
CustomizableMultipleOption: (o: CustomizableMultipleOptionFragment) => o.multipleValue,
|
54
|
+
CustomizableRadioOption: (o: CustomizableRadioOptionFragment) => o.radioValue,
|
55
|
+
}
|
56
|
+
|
57
|
+
export type SelectorsProp = keyof MissingOptionValueSelectors extends never
|
58
|
+
? { selectors?: Selectors }
|
59
|
+
: { selectors: Selectors }
|
@@ -1,10 +1,9 @@
|
|
1
1
|
import { FilterRangeTypeInput } from '@graphcommerce/graphql-mesh'
|
2
2
|
import { Money } from '@graphcommerce/magento-store'
|
3
3
|
import { extendableComponent, filterNonNullableKeys } from '@graphcommerce/next-ui'
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
5
4
|
import { Box, Slider, SxProps, Theme, useEventCallback } from '@mui/material'
|
6
5
|
import { useCallback } from 'react'
|
7
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
6
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
8
7
|
|
9
8
|
export type PriceSliderProps = {
|
10
9
|
value: FilterRangeTypeInput | null | undefined
|
@@ -1,18 +1,17 @@
|
|
1
|
-
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
1
|
+
import { ActionCardListForm, useWatch } from '@graphcommerce/ecommerce-ui'
|
2
2
|
import type { ProductAttributeFilterInput } from '@graphcommerce/graphql-mesh'
|
3
3
|
import {
|
4
|
-
ChipOverlayOrPopper,
|
5
|
-
ActionCardListForm,
|
6
4
|
ActionCard,
|
5
|
+
ChipOverlayOrPopper,
|
7
6
|
filterNonNullableKeys,
|
8
|
-
IconSvg,
|
9
7
|
iconCirle,
|
8
|
+
IconSvg,
|
10
9
|
} from '@graphcommerce/next-ui'
|
11
10
|
import { Box } from '@mui/material'
|
12
11
|
import { useMemo } from 'react'
|
13
12
|
import { isFilterTypeEqual } from '../ProductListItems/filterTypes'
|
14
13
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
15
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
14
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
16
15
|
|
17
16
|
export function ProductFilterEqualChip(props: FilterProps) {
|
18
17
|
const { aggregation } = props
|
@@ -1,20 +1,19 @@
|
|
1
|
-
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
1
|
+
import { ActionCardListForm, useWatch } from '@graphcommerce/ecommerce-ui'
|
2
2
|
import type { ProductAttributeFilterInput } from '@graphcommerce/graphql-mesh'
|
3
3
|
import {
|
4
|
-
ActionCardListForm,
|
5
4
|
ActionCard,
|
6
|
-
filterNonNullableKeys,
|
7
|
-
IconSvg,
|
8
|
-
iconCirle,
|
9
5
|
ActionCardAccordion,
|
10
6
|
Button,
|
7
|
+
filterNonNullableKeys,
|
8
|
+
iconCirle,
|
9
|
+
IconSvg,
|
11
10
|
} from '@graphcommerce/next-ui'
|
12
11
|
import { Trans } from '@lingui/react'
|
13
12
|
import { Box } from '@mui/material'
|
14
13
|
import { useMemo } from 'react'
|
15
14
|
import { isFilterTypeEqual } from '../ProductListItems/filterTypes'
|
16
15
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
17
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
16
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
18
17
|
|
19
18
|
export function ProductFilterEqualSection(props: FilterProps) {
|
20
19
|
const { aggregation } = props
|
@@ -66,7 +65,7 @@ export function ProductFilterEqualSection(props: FilterProps) {
|
|
66
65
|
multiple
|
67
66
|
layout='list'
|
68
67
|
variant='default'
|
69
|
-
size='
|
68
|
+
size='responsive'
|
70
69
|
items={items}
|
71
70
|
showMoreAfter={4}
|
72
71
|
/>
|
@@ -5,7 +5,7 @@ import { ChipOverlayOrPopper, extendableComponent } from '@graphcommerce/next-ui
|
|
5
5
|
import { isFilterTypeRange } from '../ProductListItems/filterTypes'
|
6
6
|
import { getMinMaxFromOptions, PriceSlider } from './PriceSlider'
|
7
7
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
8
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
8
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
9
9
|
|
10
10
|
const { classes } = extendableComponent('FilterRangeType', ['root', 'container', 'slider'] as const)
|
11
11
|
|
@@ -5,7 +5,7 @@ import { Trans } from '@lingui/react'
|
|
5
5
|
import { isFilterTypeRange } from '../ProductListItems/filterTypes'
|
6
6
|
import { PriceSlider, getMinMaxFromOptions } from './PriceSlider'
|
7
7
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
8
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
8
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
9
9
|
|
10
10
|
export function ProductFilterRangeSection(props: FilterProps) {
|
11
11
|
const { aggregation } = props
|