@graphcommerce/magento-product 8.1.0-canary.44 → 8.1.0-canary.45

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.
Files changed (52) hide show
  1. package/Api/ProductListItem.graphql +0 -1
  2. package/CHANGELOG.md +2 -0
  3. package/components/AddProductsToCart/AddProductsToCartButton.tsx +2 -2
  4. package/components/AddProductsToCart/AddProductsToCartFab.tsx +2 -2
  5. package/components/AddProductsToCart/AddProductsToCartForm.tsx +24 -26
  6. package/components/AddProductsToCart/AddProductsToCartSnackbar.tsx +25 -16
  7. package/components/ProductAddToCart/ProductAddToCart.tsx +6 -8
  8. package/components/ProductFiltersPro/PriceSlider.tsx +1 -2
  9. package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +1 -1
  10. package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +2 -2
  11. package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +1 -1
  12. package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +1 -1
  13. package/components/ProductFiltersPro/ProductFiltersPro.tsx +79 -17
  14. package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +17 -18
  15. package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +2 -2
  16. package/components/ProductFiltersPro/ProductFiltersProCategorySection.tsx +99 -39
  17. package/components/ProductFiltersPro/ProductFiltersProClearAll.tsx +4 -16
  18. package/components/ProductFiltersPro/ProductFiltersProLimitSection.tsx +1 -1
  19. package/components/ProductFiltersPro/ProductFiltersProNoResults.tsx +79 -0
  20. package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +1 -1
  21. package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +1 -1
  22. package/components/ProductFiltersPro/activeAggregations.ts +5 -9
  23. package/components/ProductFiltersPro/applyAggregationCount.ts +14 -8
  24. package/components/ProductFiltersPro/index.ts +4 -1
  25. package/components/ProductFiltersPro/{useClearAllFiltersHandler.ts → useProductFiltersProClearAllAction.ts} +1 -1
  26. package/components/ProductFiltersPro/useProductFiltersProHasFiltersApplied.ts +21 -0
  27. package/components/ProductList/ProductList.graphql +8 -5
  28. package/components/ProductListCount/ProductListCount.tsx +3 -1
  29. package/components/ProductListFilters/ProductFilters.graphql +7 -2
  30. package/components/ProductListFilters/ProductListFilters.graphql +1 -1
  31. package/components/ProductListItem/ProductDiscountLabel.tsx +2 -3
  32. package/components/ProductListItem/ProductListItem.tsx +3 -3
  33. package/components/ProductListItem/ProductListItemTitleAndPrice.tsx +18 -15
  34. package/components/ProductListItems/ProductListItemsBase.tsx +65 -23
  35. package/components/ProductListItems/filterTypes.tsx +14 -5
  36. package/components/ProductListItems/filteredProductList.tsx +23 -0
  37. package/components/ProductListItems/productListApplyCategoryDefaults.ts +44 -4
  38. package/components/ProductListItems/renderer.tsx +8 -2
  39. package/components/ProductListPagination/ProductListPagination.tsx +3 -1
  40. package/components/ProductListPrice/ProductListPrice.tsx +9 -4
  41. package/components/ProductListSuggestions/ProductListSuggestions.graphql +5 -0
  42. package/components/ProductListSuggestions/ProductListSuggestions.tsx +42 -0
  43. package/components/ProductPageDescription/ProductPageDescription.tsx +1 -1
  44. package/components/ProductPagePrice/ProductPagePrice.graphql +0 -6
  45. package/components/ProductPagePrice/ProductPagePrice.tsx +19 -12
  46. package/components/ProductPagePrice/ProductPagePriceTiers.tsx +4 -3
  47. package/components/ProductWeight/ProductWeight.tsx +12 -9
  48. package/components/index.ts +2 -0
  49. package/hooks/useProductList.ts +123 -0
  50. package/hooks/useProductListLink.ts +6 -3
  51. package/index.ts +1 -0
  52. package/package.json +14 -14
@@ -11,5 +11,4 @@ fragment ProductListItem on ProductInterface {
11
11
  ...ProductListPrice
12
12
  }
13
13
  }
14
- ...ConfigurableOptions
15
14
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Change Log
2
2
 
3
+ ## 8.1.0-canary.45
4
+
3
5
  ## 8.1.0-canary.44
4
6
 
5
7
  ## 8.1.0-canary.43
@@ -1,5 +1,5 @@
1
1
  import { Button, ButtonProps } from '@graphcommerce/next-ui'
2
- import { Trans } from '@lingui/react'
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 id='Add to Cart' />}
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 { i18n } from '@lingui/core'
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={i18n._(/* i18n*/ `Add to Cart`)}
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 { ExtendableComponent, nonNullable } from '@graphcommerce/next-ui'
9
- import { Box, SxProps, Theme, useThemeProps } from '@mui/material'
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
- } = useThemeProps({ name, props })
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
- {disableSuccessSnackbar ? null : (
164
- <AddProductsToCartSnackbar
165
- errorSnackbar={errorSnackbar}
166
- successSnackbar={successSnackbar}
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/react'
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 formatter = new Intl.ListFormat(useLocale(), { style: 'long', type: 'conjunction' })
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 id='View shopping cart' />
76
+ <Trans>View shopping cart</Trans>
75
77
  </Button>
76
78
  }
77
79
  >
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!'
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
- components={{ 0: <strong /> }}
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/react'
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 id='Add to Cart' />
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 id='View shopping cart' />
128
+ <Trans>View shopping cart</Trans>
129
129
  </Button>
130
130
  }
131
131
  >
132
- <Trans
133
- id='<0>{name}</0> has been added to your shopping cart!'
134
- components={{ 0: <strong /> }}
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='medium'
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 { FormAutoSubmit, useForm, UseFormProps, UseFormReturn } from '@graphcommerce/ecommerce-ui'
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, { BaseSyntheticEvent, createContext, useContext, useMemo, useRef } from '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 FilterFormContextProps = DataProps & {
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<FilterFormContextProps | null>(null)
58
+ const FilterFormContext = createContext<ProductFiltersProContext | null>(null)
33
59
 
34
- export const useProductFiltersPro = () => {
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 (!context) throw Error('useProductFiltersPro should be used inside ProductFiltersPro')
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 <FormAutoSubmit control={form.control} disabled={autoSubmitDisabled} submit={submit} />
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 opts = { scroll: scroll.get() }
90
- return (router.query.url ?? []).includes('q')
91
- ? router.replace(path, path, opts)
92
- : router.push(path, path, opts)
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: FilterFormContextProps = useMemo(
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
- [form, defaultValues, submit, appliedAggregations, filterTypes, aggregations],
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
- applyAggregationCount(aggregations, appliedAggregations, params),
38
- params,
39
- ).map((aggregation) => {
40
- const filterType = filterTypes[aggregation.attribute_code]
41
- if (!filterType) return null
42
-
43
- const Component = renderer?.[filterType]
44
- if (!Component) {
45
- if (process.env.NODE_ENV === 'development') {
46
- // eslint-disable-next-line no-console
47
- console.log(
48
- `The renderer for filterType ${filterType} can not be found, please add it to the renderer prop: renderer={{ ${filterType}: (props) => <>MYRenderer</> }}}}`,
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
- return <Component key={aggregation.attribute_code} aggregation={aggregation} {...props} />
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 { useClearAllFiltersAction } from './useClearAllFiltersHandler'
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 = useClearAllFiltersAction()
39
+ const clearAll = useProductFiltersProClearAllAction()
40
40
 
41
41
  return (
42
42
  <ChipOverlayOrPopper