@graphcommerce/magento-product 8.1.0-canary.44 → 8.1.0-canary.46
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 +0 -1
- package/CHANGELOG.md +4 -0
- package/components/AddProductsToCart/AddProductsToCartButton.tsx +2 -2
- package/components/AddProductsToCart/AddProductsToCartFab.tsx +2 -2
- package/components/AddProductsToCart/AddProductsToCartForm.tsx +24 -26
- package/components/AddProductsToCart/AddProductsToCartSnackbar.tsx +25 -16
- package/components/ProductAddToCart/ProductAddToCart.tsx +6 -8
- package/components/ProductFiltersPro/PriceSlider.tsx +1 -2
- package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +2 -2
- package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +1 -1
- package/components/ProductFiltersPro/ProductFiltersPro.tsx +79 -17
- package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +17 -18
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +2 -2
- package/components/ProductFiltersPro/ProductFiltersProCategorySection.tsx +99 -39
- package/components/ProductFiltersPro/ProductFiltersProClearAll.tsx +4 -16
- package/components/ProductFiltersPro/ProductFiltersProLimitSection.tsx +1 -1
- package/components/ProductFiltersPro/ProductFiltersProNoResults.tsx +79 -0
- package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +1 -1
- package/components/ProductFiltersPro/activeAggregations.ts +5 -9
- package/components/ProductFiltersPro/applyAggregationCount.ts +14 -8
- package/components/ProductFiltersPro/index.ts +4 -1
- package/components/ProductFiltersPro/{useClearAllFiltersHandler.ts → useProductFiltersProClearAllAction.ts} +1 -1
- package/components/ProductFiltersPro/useProductFiltersProHasFiltersApplied.ts +21 -0
- package/components/ProductList/ProductList.graphql +8 -5
- package/components/ProductListCount/ProductListCount.tsx +3 -1
- package/components/ProductListFilters/ProductFilters.graphql +7 -2
- package/components/ProductListFilters/ProductListFilters.graphql +1 -1
- package/components/ProductListItem/ProductDiscountLabel.tsx +2 -3
- package/components/ProductListItem/ProductListItem.tsx +3 -3
- package/components/ProductListItem/ProductListItemTitleAndPrice.tsx +18 -15
- package/components/ProductListItems/ProductListItemsBase.tsx +65 -23
- package/components/ProductListItems/filterTypes.tsx +14 -5
- package/components/ProductListItems/filteredProductList.tsx +23 -0
- package/components/ProductListItems/productListApplyCategoryDefaults.ts +44 -4
- package/components/ProductListItems/renderer.tsx +8 -2
- package/components/ProductListPagination/ProductListPagination.tsx +3 -1
- package/components/ProductListPrice/ProductListPrice.tsx +9 -4
- package/components/ProductListSuggestions/ProductListSuggestions.graphql +5 -0
- package/components/ProductListSuggestions/ProductListSuggestions.tsx +42 -0
- package/components/ProductPageDescription/ProductPageDescription.tsx +1 -1
- package/components/ProductPagePrice/ProductPagePrice.graphql +0 -6
- package/components/ProductPagePrice/ProductPagePrice.tsx +19 -12
- package/components/ProductPagePrice/ProductPagePriceTiers.tsx +4 -3
- package/components/ProductWeight/ProductWeight.tsx +12 -9
- package/components/index.ts +2 -0
- package/hooks/useProductList.ts +123 -0
- package/hooks/useProductListLink.ts +6 -3
- package/index.ts +1 -0
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Button, ButtonProps } from '@graphcommerce/next-ui'
|
2
|
-
import { Trans } from '@lingui/
|
2
|
+
import { Trans } from '@lingui/macro'
|
3
3
|
import {
|
4
4
|
useAddProductsToCartAction,
|
5
5
|
UseAddProductsToCartActionProps,
|
@@ -26,7 +26,7 @@ export function AddProductsToCartButton(props: AddProductsToCartButtonProps) {
|
|
26
26
|
|
27
27
|
return (
|
28
28
|
<Button type='submit' color='primary' variant='pill' size='large' {...rest} {...action}>
|
29
|
-
{children || <Trans
|
29
|
+
{children || <Trans>Add to Cart</Trans>}
|
30
30
|
</Button>
|
31
31
|
)
|
32
32
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Fab, FabProps, iconShoppingBag, iconCheckmark } from '@graphcommerce/next-ui'
|
2
|
-
import {
|
2
|
+
import { t } from '@lingui/macro'
|
3
3
|
import { SxProps, Theme } from '@mui/material'
|
4
4
|
import {
|
5
5
|
useAddProductsToCartAction,
|
@@ -22,7 +22,7 @@ export function AddProductsToCartFab(props: AddProductsToCartFabProps) {
|
|
22
22
|
{...rest}
|
23
23
|
{...action}
|
24
24
|
icon={showSuccess && !action.loading ? iconCheckmark : icon}
|
25
|
-
aria-label={
|
25
|
+
aria-label={t`Add to Cart`}
|
26
26
|
/>
|
27
27
|
)
|
28
28
|
}
|
@@ -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>>>()
|
@@ -160,12 +158,12 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
160
158
|
<Box component='form' onSubmit={submit} noValidate sx={sx} className={name}>
|
161
159
|
{children}
|
162
160
|
</Box>
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
161
|
+
<AddProductsToCartSnackbar
|
162
|
+
errorSnackbar={errorSnackbar}
|
163
|
+
successSnackbar={successSnackbar}
|
164
|
+
disableSuccessSnackbar={disableSuccessSnackbar}
|
165
|
+
{...snackbarProps}
|
166
|
+
/>
|
169
167
|
</AddProductsToCartContext.Provider>
|
170
168
|
)
|
171
169
|
}
|
@@ -6,12 +6,13 @@ import {
|
|
6
6
|
ErrorSnackbarProps,
|
7
7
|
iconChevronRight,
|
8
8
|
IconSvg,
|
9
|
+
ListFormat,
|
9
10
|
MessageSnackbar,
|
10
11
|
MessageSnackbarProps,
|
11
12
|
nonNullable,
|
12
13
|
useLocale,
|
13
14
|
} from '@graphcommerce/next-ui'
|
14
|
-
import { Trans } from '@lingui/
|
15
|
+
import { Plural, Trans } from '@lingui/macro'
|
15
16
|
import { useMemo } from 'react'
|
16
17
|
import { findAddedItems } from './findAddedItems'
|
17
18
|
import { toUserErrors } from './toUserErrors'
|
@@ -20,18 +21,19 @@ import { useFormAddProductsToCart } from './useFormAddProductsToCart'
|
|
20
21
|
export type AddProductsToCartSnackbarProps = {
|
21
22
|
errorSnackbar?: Omit<ErrorSnackbarProps, 'open'>
|
22
23
|
successSnackbar?: Omit<MessageSnackbarProps, 'open' | 'action'>
|
24
|
+
disableSuccessSnackbar?: boolean
|
23
25
|
}
|
24
26
|
|
25
27
|
export function AddProductsToCartSnackbar(props: AddProductsToCartSnackbarProps) {
|
26
|
-
const { errorSnackbar, successSnackbar } = props
|
28
|
+
const { errorSnackbar, successSnackbar, disableSuccessSnackbar } = props
|
27
29
|
const { error, data, redirect, control, submittedVariables } = useFormAddProductsToCart()
|
28
30
|
const formState = useFormState({ control })
|
29
31
|
|
30
|
-
const
|
31
|
-
|
32
|
+
const locale = useLocale()
|
32
33
|
const userErrors = toUserErrors(data)
|
33
34
|
|
34
35
|
const showSuccess =
|
36
|
+
!disableSuccessSnackbar &&
|
35
37
|
!formState.isSubmitting &&
|
36
38
|
formState.isSubmitSuccessful &&
|
37
39
|
!error?.message &&
|
@@ -71,22 +73,29 @@ export function AddProductsToCartSnackbar(props: AddProductsToCartSnackbarProps)
|
|
71
73
|
endIcon={<IconSvg src={iconChevronRight} />}
|
72
74
|
sx={{ display: 'flex' }}
|
73
75
|
>
|
74
|
-
<Trans
|
76
|
+
<Trans>View shopping cart</Trans>
|
75
77
|
</Button>
|
76
78
|
}
|
77
79
|
>
|
78
|
-
<
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
<Plural
|
81
|
+
value={addedItems.length}
|
82
|
+
one={
|
83
|
+
<Trans>
|
84
|
+
<ListFormat listStyle='long' type='conjunction'>
|
85
|
+
{addedItems.map((item) => item?.itemInCart?.product.name).filter(nonNullable)}
|
86
|
+
</ListFormat>{' '}
|
87
|
+
has been added to your shopping cart
|
88
|
+
</Trans>
|
89
|
+
}
|
90
|
+
two={
|
91
|
+
<Trans>
|
92
|
+
<ListFormat listStyle='long' type='conjunction'>
|
93
|
+
{addedItems.map((item) => item?.itemInCart?.product.name).filter(nonNullable)}
|
94
|
+
</ListFormat>{' '}
|
95
|
+
have been added to your shopping cart!
|
96
|
+
</Trans>
|
83
97
|
}
|
84
|
-
|
85
|
-
values={{
|
86
|
-
name: formatter.format(
|
87
|
-
addedItems.map((item) => item?.itemInCart?.product.name).filter(nonNullable),
|
88
|
-
),
|
89
|
-
}}
|
98
|
+
other={<Trans># products have been added to your shopping cart!</Trans>}
|
90
99
|
/>
|
91
100
|
</MessageSnackbar>
|
92
101
|
)}
|
@@ -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,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
|
@@ -12,7 +12,7 @@ import { Box } from '@mui/material'
|
|
12
12
|
import { useMemo } from 'react'
|
13
13
|
import { isFilterTypeEqual } from '../ProductListItems/filterTypes'
|
14
14
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
15
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
15
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
16
16
|
|
17
17
|
export function ProductFilterEqualChip(props: FilterProps) {
|
18
18
|
const { aggregation } = props
|
@@ -14,7 +14,7 @@ import { Box } from '@mui/material'
|
|
14
14
|
import { useMemo } from 'react'
|
15
15
|
import { isFilterTypeEqual } from '../ProductListItems/filterTypes'
|
16
16
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
17
|
-
import { FilterProps } from './ProductFiltersProAggregations'
|
17
|
+
import type { FilterProps } from './ProductFiltersProAggregations'
|
18
18
|
|
19
19
|
export function ProductFilterEqualSection(props: FilterProps) {
|
20
20
|
const { aggregation } = props
|
@@ -66,7 +66,7 @@ export function ProductFilterEqualSection(props: FilterProps) {
|
|
66
66
|
multiple
|
67
67
|
layout='list'
|
68
68
|
variant='default'
|
69
|
-
size='
|
69
|
+
size='responsive'
|
70
70
|
items={items}
|
71
71
|
showMoreAfter={4}
|
72
72
|
/>
|
@@ -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
|
@@ -1,9 +1,25 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
DeepPartial,
|
3
|
+
FormAutoSubmit,
|
4
|
+
useForm,
|
5
|
+
UseFormProps,
|
6
|
+
UseFormReturn,
|
7
|
+
WatchObserver,
|
8
|
+
} from '@graphcommerce/ecommerce-ui'
|
2
9
|
import { useMatchMediaMotionValue, useMemoObject } from '@graphcommerce/next-ui'
|
3
10
|
import { Theme, useEventCallback, useMediaQuery, useTheme } from '@mui/material'
|
4
11
|
import { m, useTransform } from 'framer-motion'
|
5
12
|
import { useRouter } from 'next/router'
|
6
|
-
import React, {
|
13
|
+
import React, {
|
14
|
+
BaseSyntheticEvent,
|
15
|
+
createContext,
|
16
|
+
MutableRefObject,
|
17
|
+
useContext,
|
18
|
+
useEffect,
|
19
|
+
useMemo,
|
20
|
+
useRef,
|
21
|
+
} from 'react'
|
22
|
+
import type { Subscription } from 'react-hook-form/dist/utils/createSubject'
|
7
23
|
import { productListLinkFromFilter } from '../../hooks/useProductListLink'
|
8
24
|
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
9
25
|
import {
|
@@ -17,23 +33,40 @@ type DataProps = {
|
|
17
33
|
appliedAggregations?: ProductListFiltersFragment['aggregations']
|
18
34
|
} & ProductListFiltersFragment
|
19
35
|
|
20
|
-
type
|
36
|
+
export type ProductFiltersProContext = DataProps & {
|
21
37
|
/**
|
22
38
|
* Watch and formState are known to cause performance issues.
|
23
39
|
*
|
24
40
|
* - `watch` -> `useWatch`
|
25
41
|
* - `formState` -> `useFormState`
|
26
42
|
*/
|
27
|
-
form: Omit<UseFormReturn<ProductFilterParams>, 'formState' | 'watch'>
|
43
|
+
form: Omit<UseFormReturn<ProductFilterParams>, 'formState' | 'watch'> & {
|
44
|
+
watch: (
|
45
|
+
callback: WatchObserver<ProductFilterParams>,
|
46
|
+
defaultValues?: DeepPartial<ProductFilterParams>,
|
47
|
+
) => Subscription
|
48
|
+
}
|
49
|
+
/**
|
50
|
+
* Parameters of the currently displayed items.
|
51
|
+
*
|
52
|
+
* To get active form values use `useWatch`.
|
53
|
+
*/
|
28
54
|
params: ProductFilterParams
|
29
55
|
submit: (e?: BaseSyntheticEvent<object, any, any> | undefined) => Promise<void>
|
30
56
|
}
|
31
57
|
|
32
|
-
const FilterFormContext = createContext<
|
58
|
+
const FilterFormContext = createContext<ProductFiltersProContext | null>(null)
|
33
59
|
|
34
|
-
export const
|
60
|
+
export const globalFormContextRef: MutableRefObject<ProductFiltersProContext | null> = {
|
61
|
+
current: null,
|
62
|
+
}
|
63
|
+
|
64
|
+
export function useProductFiltersPro(optional: true): ProductFiltersProContext | null
|
65
|
+
export function useProductFiltersPro(optional?: false): ProductFiltersProContext
|
66
|
+
export function useProductFiltersPro(optional: boolean = false) {
|
35
67
|
const context = useContext(FilterFormContext)
|
36
|
-
if (!
|
68
|
+
if (!optional && !context)
|
69
|
+
throw Error('useProductFiltersPro should be used inside ProductFiltersPro')
|
37
70
|
return context
|
38
71
|
}
|
39
72
|
|
@@ -47,6 +80,11 @@ export type FilterFormProviderProps = Omit<
|
|
47
80
|
* Whether the filter should scroll to the products list and whether to submit the form on change.
|
48
81
|
*/
|
49
82
|
autoSubmitMd?: boolean
|
83
|
+
|
84
|
+
handleSubmit?: (
|
85
|
+
formValues: ProductFilterParams,
|
86
|
+
next: (shallow?: boolean, replace?: boolean) => Promise<void>,
|
87
|
+
) => Promise<void> | void
|
50
88
|
} & DataProps
|
51
89
|
|
52
90
|
function AutoSubmitSidebarDesktop() {
|
@@ -57,7 +95,15 @@ function AutoSubmitSidebarDesktop() {
|
|
57
95
|
defaultMatches: false,
|
58
96
|
})
|
59
97
|
|
60
|
-
return
|
98
|
+
return (
|
99
|
+
<FormAutoSubmit
|
100
|
+
control={form.control}
|
101
|
+
disabled={autoSubmitDisabled}
|
102
|
+
submit={submit}
|
103
|
+
leading
|
104
|
+
name={['filters', 'url', 'sort', 'pageSize', 'currentPage', 'dir']}
|
105
|
+
/>
|
106
|
+
)
|
61
107
|
}
|
62
108
|
|
63
109
|
export function ProductFiltersPro(props: FilterFormProviderProps) {
|
@@ -68,6 +114,7 @@ export function ProductFiltersPro(props: FilterFormProviderProps) {
|
|
68
114
|
appliedAggregations,
|
69
115
|
filterTypes,
|
70
116
|
autoSubmitMd = false,
|
117
|
+
handleSubmit,
|
71
118
|
...formProps
|
72
119
|
} = props
|
73
120
|
|
@@ -86,30 +133,45 @@ export function ProductFiltersPro(props: FilterFormProviderProps) {
|
|
86
133
|
const path = productListLinkFromFilter({ ...formValues, currentPage: 1 })
|
87
134
|
if (router.asPath === path) return false
|
88
135
|
|
89
|
-
const
|
90
|
-
|
91
|
-
|
92
|
-
|
136
|
+
const isSearch = router.asPath.startsWith('/search')
|
137
|
+
const isFilter = (router.query.url ?? []).includes('q')
|
138
|
+
|
139
|
+
const next = async (shallow = false, replace: boolean = isSearch || isFilter) => {
|
140
|
+
const opts = { shallow, scroll: scroll.get() }
|
141
|
+
await (replace ? router.replace(path, path, opts) : router.push(path, path, opts))
|
142
|
+
}
|
143
|
+
|
144
|
+
if (handleSubmit) return handleSubmit(formValues, next)
|
145
|
+
return next()
|
93
146
|
}),
|
94
147
|
)
|
95
148
|
|
96
|
-
const filterFormContext
|
97
|
-
|
149
|
+
const filterFormContext = useMemo(() => {
|
150
|
+
const ctx: ProductFiltersProContext = {
|
98
151
|
form,
|
99
152
|
params: defaultValues,
|
100
153
|
submit,
|
101
154
|
appliedAggregations,
|
102
155
|
filterTypes,
|
103
156
|
aggregations,
|
104
|
-
}
|
105
|
-
|
157
|
+
}
|
158
|
+
globalFormContextRef.current = ctx
|
159
|
+
return ctx
|
160
|
+
}, [form, defaultValues, submit, appliedAggregations, filterTypes, aggregations])
|
161
|
+
|
162
|
+
// When the component unmounts, we want to clear the global filter form
|
163
|
+
useEffect(
|
164
|
+
() => () => {
|
165
|
+
globalFormContextRef.current = null
|
166
|
+
},
|
167
|
+
[],
|
106
168
|
)
|
107
169
|
|
108
170
|
return (
|
109
171
|
<FilterFormContext.Provider value={filterFormContext}>
|
110
172
|
<m.form ref={ref} noValidate onSubmit={submit} id='products' style={{ scrollMarginTop }} />
|
111
|
-
{autoSubmitMd && <AutoSubmitSidebarDesktop />}
|
112
173
|
{children}
|
174
|
+
{autoSubmitMd && <AutoSubmitSidebarDesktop />}
|
113
175
|
</FilterFormContext.Provider>
|
114
176
|
)
|
115
177
|
}
|
@@ -33,26 +33,25 @@ export function ProductFiltersProAggregations(props: ProductFiltersProAggregatio
|
|
33
33
|
|
34
34
|
return (
|
35
35
|
<>
|
36
|
-
{excludeCategory(
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
36
|
+
{excludeCategory(applyAggregationCount(aggregations, appliedAggregations, params)).map(
|
37
|
+
(aggregation) => {
|
38
|
+
const filterType = filterTypes[aggregation.attribute_code]
|
39
|
+
if (!filterType) return null
|
40
|
+
|
41
|
+
const Component = renderer?.[filterType]
|
42
|
+
if (!Component) {
|
43
|
+
if (process.env.NODE_ENV === 'development') {
|
44
|
+
// eslint-disable-next-line no-console
|
45
|
+
console.log(
|
46
|
+
`The renderer for filterType ${filterType} can not be found, please add it to the renderer prop: renderer={{ ${filterType}: (props) => <>MYRenderer</> }}}}`,
|
47
|
+
)
|
48
|
+
}
|
49
|
+
return null
|
50
50
|
}
|
51
|
-
return null
|
52
|
-
}
|
53
51
|
|
54
|
-
|
55
|
-
|
52
|
+
return <Component key={aggregation.attribute_code} aggregation={aggregation} {...props} />
|
53
|
+
},
|
54
|
+
)}
|
56
55
|
</>
|
57
56
|
)
|
58
57
|
}
|
@@ -13,7 +13,7 @@ import {
|
|
13
13
|
} from './ProductFiltersProSortSection'
|
14
14
|
import { activeAggregations } from './activeAggregations'
|
15
15
|
import { applyAggregationCount } from './applyAggregationCount'
|
16
|
-
import {
|
16
|
+
import { useProductFiltersProClearAllAction } from './useProductFiltersProClearAllAction'
|
17
17
|
|
18
18
|
export type ProductFiltersProAllFiltersChipProps = ProductFiltersProAggregationsProps &
|
19
19
|
ProductFiltersProSortSectionProps &
|
@@ -36,7 +36,7 @@ export function ProductFiltersProAllFiltersChip(props: ProductFiltersProAllFilte
|
|
36
36
|
const allFilters = [...activeFilters, sort].filter(Boolean)
|
37
37
|
const hasFilters = allFilters.length > 0
|
38
38
|
|
39
|
-
const clearAll =
|
39
|
+
const clearAll = useProductFiltersProClearAllAction()
|
40
40
|
|
41
41
|
return (
|
42
42
|
<ChipOverlayOrPopper
|