@graphcommerce/magento-product 7.0.0-canary.21 → 7.0.0
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/CHANGELOG.md +235 -1
- package/Config.graphqls +12 -2
- package/components/AddProductsToCart/AddProductsToCart.graphql +1 -0
- package/components/AddProductsToCart/AddProductsToCartError.tsx +2 -3
- package/components/AddProductsToCart/AddProductsToCartForm.tsx +1 -2
- package/components/AddProductsToCart/AddProductsToCartQuantity.tsx +3 -2
- package/components/AddProductsToCart/useAddProductsToCartAction.ts +2 -3
- package/components/AddProductsToCart/useFormAddProductsToCart.ts +3 -1
- package/components/JsonLdProduct/JsonLdProduct.graphql +1 -1
- package/components/JsonLdProduct/ProductPageJsonLd.tsx +12 -0
- package/components/JsonLdProduct/index.ts +2 -0
- package/components/ProductCustomizable/ProductCustomizable.tsx +4 -5
- package/components/ProductFiltersPro/PriceSlider.tsx +7 -2
- package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +36 -37
- package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +19 -23
- package/components/ProductFiltersPro/ProductFiltersPro.tsx +35 -18
- package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +5 -6
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +20 -43
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersSidebar.tsx +32 -0
- package/components/ProductFiltersPro/ProductFiltersProClearAll.tsx +48 -0
- package/components/ProductFiltersPro/ProductFiltersProLayoutSidebar.tsx +100 -0
- package/components/ProductFiltersPro/ProductFiltersProLimitChip.tsx +2 -2
- package/components/ProductFiltersPro/ProductFiltersProLimitSection.tsx +35 -32
- package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +3 -2
- package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +31 -31
- package/components/ProductFiltersPro/index.ts +3 -0
- package/components/ProductFiltersPro/useClearAllFiltersHandler.ts +31 -0
- package/components/ProductListCount/ProductListCount.tsx +12 -6
- package/components/ProductListFilters/FilterEqualType.tsx +1 -0
- package/components/ProductListFilters/FilterRangeType.tsx +1 -0
- package/components/ProductListItems/ProductListItemsBase.tsx +58 -38
- package/components/ProductListItems/filterTypes.tsx +4 -5
- package/components/ProductListLink/ProductListLink.tsx +1 -0
- package/components/ProductListPagination/ProductListPagination.tsx +14 -7
- package/components/ProductListPrice/ProductListPrice.tsx +1 -1
- package/components/ProductListPrice/index.ts +2 -0
- package/components/ProductPage/ProductPageAddToCartRow.tsx +3 -2
- package/components/ProductPageBreadcrumb/ProductPageBreadcrumb.tsx +2 -2
- package/components/ProductPageDescription/ProductPageDescription.graphql +1 -0
- package/components/ProductPageDescription/ProductPageDescription.tsx +6 -4
- package/components/ProductPageGallery/ProductPageGallery.graphql +1 -0
- package/components/ProductPageGallery/ProductPageGallery.tsx +6 -8
- package/components/ProductPageMeta/ProductPageMeta.graphql +5 -3
- package/components/ProductPageMeta/ProductPageMeta.tsx +18 -21
- package/components/ProductPageName/ProductPageName.graphql +4 -0
- package/components/ProductPageName/ProductPageName.tsx +10 -0
- package/components/ProductPageName/index.ts +1 -0
- package/components/ProductPagePrice/ProductPagePrice.graphql +1 -0
- package/components/ProductPagePrice/ProductPagePrice.tsx +2 -2
- package/components/ProductShortDescription/ProductShortDescription.graphql +1 -0
- package/components/ProductShortDescription/ProductShortDescription.tsx +6 -2
- package/components/ProductSpecs/ProductSpecs.tsx +7 -2
- package/components/index.ts +5 -2
- package/hooks/useProductListLink.ts +2 -2
- package/hooks/useProductListLinkReplace.ts +2 -2
- package/index.ts +1 -0
- package/package.json +16 -15
- package/components/AddProductsToCart/AddProductsToCartIndex.tsx +0 -3
- package/components/ProductFiltersPro/useFilterActions.ts +0 -61
- package/components/ProductListItems/ProductListItems.tsx +0 -6
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { useForm, UseFormProps, UseFormReturn } from '@graphcommerce/ecommerce-ui'
|
|
2
2
|
import { useMemoObject } from '@graphcommerce/next-ui'
|
|
3
|
-
import
|
|
3
|
+
import { useEventCallback } from '@mui/material'
|
|
4
|
+
import React, { BaseSyntheticEvent, createContext, useContext, useMemo } from 'react'
|
|
4
5
|
import { useProductListLinkReplace } from '../../hooks/useProductListLinkReplace'
|
|
6
|
+
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
|
5
7
|
import {
|
|
6
8
|
ProductFilterParams,
|
|
7
9
|
ProductListParams,
|
|
@@ -9,7 +11,12 @@ import {
|
|
|
9
11
|
toProductListParams,
|
|
10
12
|
} from '../ProductListItems/filterTypes'
|
|
11
13
|
|
|
12
|
-
type
|
|
14
|
+
type DataProps = {
|
|
15
|
+
filterTypes: Record<string, string | undefined>
|
|
16
|
+
appliedAggregations?: ProductListFiltersFragment['aggregations']
|
|
17
|
+
} & ProductListFiltersFragment
|
|
18
|
+
|
|
19
|
+
type FilterFormContextProps = DataProps & {
|
|
13
20
|
/**
|
|
14
21
|
* Watch and formState are known to cause performance issues.
|
|
15
22
|
*
|
|
@@ -32,30 +39,40 @@ export const useProductFiltersPro = () => {
|
|
|
32
39
|
export type FilterFormProviderProps = Omit<
|
|
33
40
|
UseFormProps<ProductFilterParams>,
|
|
34
41
|
'values' | 'defaultValues'
|
|
35
|
-
> & {
|
|
42
|
+
> & {
|
|
43
|
+
children: React.ReactNode
|
|
44
|
+
params: ProductListParams
|
|
45
|
+
} & DataProps
|
|
36
46
|
|
|
37
47
|
export function ProductFiltersPro(props: FilterFormProviderProps) {
|
|
38
|
-
const { children, params, ...formProps } = props
|
|
48
|
+
const { children, params, aggregations, appliedAggregations, filterTypes, ...formProps } = props
|
|
39
49
|
|
|
40
|
-
const
|
|
41
|
-
const form = useForm<ProductFilterParams>({
|
|
42
|
-
values: fitlerParams,
|
|
43
|
-
...formProps,
|
|
44
|
-
})
|
|
45
|
-
const { handleSubmit } = form
|
|
50
|
+
const defaultValues = useMemoObject(toFilterParams(params))
|
|
51
|
+
const form = useForm<ProductFilterParams>({ defaultValues, ...formProps })
|
|
46
52
|
|
|
47
53
|
const push = useProductListLinkReplace({ scroll: false })
|
|
48
|
-
const submit =
|
|
49
|
-
|
|
54
|
+
const submit = useEventCallback(
|
|
55
|
+
form.handleSubmit(async (formValues) =>
|
|
56
|
+
push({ ...toProductListParams(formValues), currentPage: 1 }),
|
|
57
|
+
),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
const filterFormContext: FilterFormContextProps = useMemo(
|
|
61
|
+
() => ({
|
|
62
|
+
form,
|
|
63
|
+
params: defaultValues,
|
|
64
|
+
submit,
|
|
65
|
+
appliedAggregations,
|
|
66
|
+
filterTypes,
|
|
67
|
+
aggregations,
|
|
68
|
+
}),
|
|
69
|
+
[form, defaultValues, submit, appliedAggregations, filterTypes, aggregations],
|
|
50
70
|
)
|
|
51
71
|
|
|
52
72
|
return (
|
|
53
|
-
<FilterFormContext.Provider
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
<form noValidate onSubmit={submit}>
|
|
57
|
-
{children}
|
|
58
|
-
</form>
|
|
73
|
+
<FilterFormContext.Provider value={filterFormContext}>
|
|
74
|
+
<form noValidate onSubmit={submit} id='products' />
|
|
75
|
+
{children}
|
|
59
76
|
</FilterFormContext.Provider>
|
|
60
77
|
)
|
|
61
78
|
}
|
|
@@ -10,14 +10,12 @@ export type FilterProps = {
|
|
|
10
10
|
export type FilterRenderer = Record<string, React.FC<FilterProps>>
|
|
11
11
|
|
|
12
12
|
export type ProductFiltersProAggregationsProps = {
|
|
13
|
-
filterTypes: Record<string, string | undefined>
|
|
14
13
|
renderer?: FilterRenderer
|
|
15
|
-
|
|
16
|
-
} & ProductListFiltersFragment
|
|
14
|
+
}
|
|
17
15
|
|
|
18
16
|
export function ProductFiltersProAggregations(props: ProductFiltersProAggregationsProps) {
|
|
19
|
-
const {
|
|
20
|
-
const { params } = useProductFiltersPro()
|
|
17
|
+
const { renderer } = props
|
|
18
|
+
const { params, aggregations, appliedAggregations, filterTypes } = useProductFiltersPro()
|
|
21
19
|
|
|
22
20
|
return (
|
|
23
21
|
<>
|
|
@@ -31,8 +29,9 @@ export function ProductFiltersProAggregations(props: ProductFiltersProAggregatio
|
|
|
31
29
|
const Component = renderer?.[filterType]
|
|
32
30
|
if (!Component) {
|
|
33
31
|
if (process.env.NODE_ENV === 'development') {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
34
33
|
console.log(
|
|
35
|
-
`The renderer for
|
|
34
|
+
`The renderer for filterType ${filterType} can not be found, please add it to the renderer prop: renderer={{ ${filterType}: (props) => <>MYRenderer</> }}}}`,
|
|
36
35
|
)
|
|
37
36
|
}
|
|
38
37
|
return null
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ChipOverlayOrPopper,
|
|
3
|
-
ChipOverlayOrPopperProps,
|
|
4
|
-
filterNonNullableKeys,
|
|
5
|
-
} from '@graphcommerce/next-ui'
|
|
1
|
+
import { ChipOverlayOrPopper, ChipOverlayOrPopperProps } from '@graphcommerce/next-ui'
|
|
6
2
|
import { Trans } from '@lingui/react'
|
|
7
|
-
import { Box } from '@mui/material'
|
|
8
|
-
import { activeAggregations } from './activeAggregations'
|
|
9
|
-
import { applyAggregationCount } from './applyAggregationCount'
|
|
10
3
|
import { ProductFilterEqualSection } from './ProductFilterEqualSection'
|
|
11
4
|
import { ProductFilterRangeSection } from './ProductFilterRangeSection'
|
|
12
5
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
@@ -19,52 +12,44 @@ import {
|
|
|
19
12
|
ProductFiltersProSortSection,
|
|
20
13
|
ProductFiltersProSortSectionProps,
|
|
21
14
|
} from './ProductFiltersProSortSection'
|
|
15
|
+
import { activeAggregations } from './activeAggregations'
|
|
16
|
+
import { applyAggregationCount } from './applyAggregationCount'
|
|
17
|
+
import { useClearAllFiltersAction } from './useClearAllFiltersHandler'
|
|
22
18
|
|
|
23
|
-
type
|
|
19
|
+
export type ProductFiltersProAllFiltersChipProps = ProductFiltersProAggregationsProps &
|
|
24
20
|
ProductFiltersProSortSectionProps &
|
|
25
21
|
Omit<
|
|
26
22
|
ChipOverlayOrPopperProps,
|
|
27
23
|
'label' | 'selected' | 'selectedLabel' | 'onApply' | 'onReset' | 'onClose' | 'children'
|
|
28
24
|
>
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
renderer,
|
|
38
|
-
...rest
|
|
39
|
-
} = props
|
|
26
|
+
const defaultRenderer = {
|
|
27
|
+
FilterRangeTypeInput: ProductFilterRangeSection,
|
|
28
|
+
FilterEqualTypeInput: ProductFilterEqualSection,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function ProductFiltersProAllFiltersChip(props: ProductFiltersProAllFiltersChipProps) {
|
|
32
|
+
const { sort_fields, total_count, renderer, ...rest } = props
|
|
40
33
|
|
|
41
|
-
const {
|
|
34
|
+
const { submit, params, aggregations, appliedAggregations } = useProductFiltersPro()
|
|
42
35
|
const { sort } = params
|
|
43
36
|
|
|
44
37
|
const activeFilters = activeAggregations(
|
|
45
|
-
applyAggregationCount(aggregations,
|
|
38
|
+
applyAggregationCount(aggregations, appliedAggregations, params),
|
|
46
39
|
params,
|
|
47
40
|
).map(({ label }) => label)
|
|
48
41
|
|
|
49
42
|
const allFilters = [...activeFilters, sort].filter(Boolean)
|
|
50
43
|
const hasFilters = allFilters.length > 0
|
|
51
44
|
|
|
45
|
+
const clearAll = useClearAllFiltersAction()
|
|
46
|
+
|
|
52
47
|
return (
|
|
53
48
|
<ChipOverlayOrPopper
|
|
54
49
|
label={<Trans id='All filters' />}
|
|
55
50
|
chipProps={{ variant: 'outlined' }}
|
|
56
51
|
onApply={submit}
|
|
57
|
-
onReset={
|
|
58
|
-
hasFilters
|
|
59
|
-
? () => {
|
|
60
|
-
form.setValue('filters', { category_uid: params.filters.category_uid })
|
|
61
|
-
form.setValue('currentPage', 1)
|
|
62
|
-
form.setValue('sort', null)
|
|
63
|
-
form.setValue('dir', null)
|
|
64
|
-
return submit()
|
|
65
|
-
}
|
|
66
|
-
: undefined
|
|
67
|
-
}
|
|
52
|
+
onReset={hasFilters ? clearAll : undefined}
|
|
68
53
|
onClose={submit}
|
|
69
54
|
selectedLabel={allFilters}
|
|
70
55
|
selected={hasFilters}
|
|
@@ -73,19 +58,11 @@ export function ProductFiltersProAllFiltersChip(props: AllFiltersChip) {
|
|
|
73
58
|
{...rest}
|
|
74
59
|
>
|
|
75
60
|
{() => (
|
|
76
|
-
|
|
61
|
+
<>
|
|
77
62
|
<ProductFiltersProSortSection sort_fields={sort_fields} total_count={total_count} />
|
|
78
63
|
<ProductFiltersProLimitSection />
|
|
79
|
-
<ProductFiltersProAggregations
|
|
80
|
-
|
|
81
|
-
aggregations={aggregations}
|
|
82
|
-
appliedAggregations={aggregationsCount}
|
|
83
|
-
renderer={{
|
|
84
|
-
FilterRangeTypeInput: ProductFilterRangeSection,
|
|
85
|
-
FilterEqualTypeInput: ProductFilterEqualSection,
|
|
86
|
-
}}
|
|
87
|
-
/>
|
|
88
|
-
</Box>
|
|
64
|
+
<ProductFiltersProAggregations renderer={{ ...defaultRenderer, ...renderer }} />
|
|
65
|
+
</>
|
|
89
66
|
)}
|
|
90
67
|
</ChipOverlayOrPopper>
|
|
91
68
|
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Box, SxProps, Theme } from '@mui/material'
|
|
2
|
+
import { ProductFilterEqualSection } from './ProductFilterEqualSection'
|
|
3
|
+
import { ProductFilterRangeSection } from './ProductFilterRangeSection'
|
|
4
|
+
import {
|
|
5
|
+
ProductFiltersProAggregations,
|
|
6
|
+
ProductFiltersProAggregationsProps,
|
|
7
|
+
} from './ProductFiltersProAggregations'
|
|
8
|
+
import { ProductFiltersProLimitSection } from './ProductFiltersProLimitSection'
|
|
9
|
+
import {
|
|
10
|
+
ProductFiltersProSortSection,
|
|
11
|
+
ProductFiltersProSortSectionProps,
|
|
12
|
+
} from './ProductFiltersProSortSection'
|
|
13
|
+
|
|
14
|
+
export type ProductFiltersProAllFiltersSidebarProps = ProductFiltersProAggregationsProps &
|
|
15
|
+
ProductFiltersProSortSectionProps & { sx?: SxProps<Theme> }
|
|
16
|
+
|
|
17
|
+
const defaultRenderer = {
|
|
18
|
+
FilterRangeTypeInput: ProductFilterRangeSection,
|
|
19
|
+
FilterEqualTypeInput: ProductFilterEqualSection,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function ProductFiltersProAllFiltersSidebar(props: ProductFiltersProAllFiltersSidebarProps) {
|
|
23
|
+
const { sort_fields, total_count, renderer, sx = [] } = props
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Box sx={[{ display: { xs: 'none', md: 'grid' } }, ...(Array.isArray(sx) ? sx : [sx])]}>
|
|
27
|
+
<ProductFiltersProSortSection sort_fields={sort_fields} total_count={total_count} />
|
|
28
|
+
<ProductFiltersProLimitSection />
|
|
29
|
+
<ProductFiltersProAggregations renderer={{ ...defaultRenderer, ...renderer }} />
|
|
30
|
+
</Box>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Button } from '@graphcommerce/next-ui'
|
|
2
|
+
import { Trans } from '@lingui/react'
|
|
3
|
+
import { SxProps, Theme } from '@mui/material'
|
|
4
|
+
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
5
|
+
import { ProductFiltersProAggregationsProps } from './ProductFiltersProAggregations'
|
|
6
|
+
import { activeAggregations } from './activeAggregations'
|
|
7
|
+
import { applyAggregationCount } from './applyAggregationCount'
|
|
8
|
+
import { useClearAllFiltersAction } from './useClearAllFiltersHandler'
|
|
9
|
+
|
|
10
|
+
type AllFiltersSidebar = ProductFiltersProAggregationsProps & {
|
|
11
|
+
sx?: SxProps<Theme>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function ProductFiltersProClearAll(props: AllFiltersSidebar) {
|
|
15
|
+
const { sx = [] } = props
|
|
16
|
+
|
|
17
|
+
const { params, aggregations, appliedAggregations } = useProductFiltersPro()
|
|
18
|
+
const { sort } = params
|
|
19
|
+
|
|
20
|
+
const clearAll = useClearAllFiltersAction()
|
|
21
|
+
|
|
22
|
+
const activeFilters = activeAggregations(
|
|
23
|
+
applyAggregationCount(aggregations, appliedAggregations, params),
|
|
24
|
+
params,
|
|
25
|
+
).map(({ label }) => label)
|
|
26
|
+
|
|
27
|
+
const allFilters = [...activeFilters, sort].filter(Boolean)
|
|
28
|
+
const hasFilters = allFilters.length > 0
|
|
29
|
+
|
|
30
|
+
if (!hasFilters) return null
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Button
|
|
34
|
+
sx={sx}
|
|
35
|
+
fullWidth
|
|
36
|
+
variant='pill'
|
|
37
|
+
size='medium'
|
|
38
|
+
color='inherit'
|
|
39
|
+
disableElevation
|
|
40
|
+
onClick={(e) => {
|
|
41
|
+
e.preventDefault()
|
|
42
|
+
return clearAll()
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
<Trans id='Clear all filters' />
|
|
46
|
+
</Button>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { FormAutoSubmit } from '@graphcommerce/ecommerce-ui'
|
|
2
|
+
import { extendableComponent, StickyBelowHeader } from '@graphcommerce/next-ui'
|
|
3
|
+
import { Box, Container, Theme, useMediaQuery } from '@mui/material'
|
|
4
|
+
import React from 'react'
|
|
5
|
+
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
6
|
+
|
|
7
|
+
export type ProductFiltersProLayoutSidebarProps = {
|
|
8
|
+
items: React.ReactNode
|
|
9
|
+
clearAll?: React.ReactNode
|
|
10
|
+
horizontalFilters: React.ReactNode
|
|
11
|
+
sidebarFilters?: React.ReactNode
|
|
12
|
+
count?: React.ReactNode
|
|
13
|
+
pagination: React.ReactNode
|
|
14
|
+
header?: React.ReactNode
|
|
15
|
+
} & Partial<OwnerProps>
|
|
16
|
+
|
|
17
|
+
type OwnerProps = {
|
|
18
|
+
headerPosition: 'before'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const name = 'ProductFiltersProLayoutSidebar' as const
|
|
22
|
+
const parts = ['root', 'content'] as const
|
|
23
|
+
const { withState } = extendableComponent<OwnerProps, typeof name, typeof parts>(name, parts)
|
|
24
|
+
|
|
25
|
+
export function ProductFiltersProLayoutSidebar(props: ProductFiltersProLayoutSidebarProps) {
|
|
26
|
+
const {
|
|
27
|
+
items,
|
|
28
|
+
clearAll,
|
|
29
|
+
horizontalFilters,
|
|
30
|
+
count,
|
|
31
|
+
pagination,
|
|
32
|
+
sidebarFilters,
|
|
33
|
+
header,
|
|
34
|
+
headerPosition = 'before',
|
|
35
|
+
} = props
|
|
36
|
+
|
|
37
|
+
const { form, submit } = useProductFiltersPro()
|
|
38
|
+
const classes = withState({ headerPosition })
|
|
39
|
+
|
|
40
|
+
// We only need to auto-submit when the layout is not sidebar and we're viewing on desktop
|
|
41
|
+
const m = useMediaQuery<Theme>((t) => t.breakpoints.down('md'), { defaultMatches: false })
|
|
42
|
+
const autoSubmitDisabled = m
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{headerPosition === 'before' ? header : null}
|
|
47
|
+
|
|
48
|
+
<FormAutoSubmit control={form.control} disabled={autoSubmitDisabled} submit={submit} />
|
|
49
|
+
|
|
50
|
+
<StickyBelowHeader sx={{ display: { md: 'none' } }}>{horizontalFilters}</StickyBelowHeader>
|
|
51
|
+
|
|
52
|
+
<Container
|
|
53
|
+
maxWidth={false}
|
|
54
|
+
className={classes.content}
|
|
55
|
+
sx={(theme) => ({
|
|
56
|
+
display: 'grid',
|
|
57
|
+
gridTemplate: {
|
|
58
|
+
xs: `
|
|
59
|
+
"beforeContent" auto
|
|
60
|
+
"items" auto
|
|
61
|
+
"afterContent" auto
|
|
62
|
+
`,
|
|
63
|
+
md: `
|
|
64
|
+
"topleft beforeContent" auto
|
|
65
|
+
"sidebar items" min-content
|
|
66
|
+
"sidebar afterContent" 1fr
|
|
67
|
+
/300px auto
|
|
68
|
+
`,
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
columnGap: { md: theme.spacings.md, xl: theme.spacings.xxl },
|
|
72
|
+
|
|
73
|
+
'& .ProductListItemsBase-root.sizeNormal': {
|
|
74
|
+
gridTemplateColumns: {
|
|
75
|
+
xs: 'repeat(2, 1fr)',
|
|
76
|
+
lg: 'repeat(3, 1fr)',
|
|
77
|
+
xl: 'repeat(4, 1fr)',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
})}
|
|
81
|
+
>
|
|
82
|
+
<Box gridArea='topleft' sx={{ display: { xs: 'none', md: 'block' }, alignSelf: 'center' }}>
|
|
83
|
+
{clearAll}
|
|
84
|
+
</Box>
|
|
85
|
+
{sidebarFilters && (
|
|
86
|
+
<Box gridArea='sidebar' sx={{ display: { xs: 'none', md: 'block' } }}>
|
|
87
|
+
{sidebarFilters}
|
|
88
|
+
</Box>
|
|
89
|
+
)}
|
|
90
|
+
|
|
91
|
+
<Box gridArea='beforeContent' sx={{ mt: { md: 0 } }}>
|
|
92
|
+
{count}
|
|
93
|
+
</Box>
|
|
94
|
+
<Box gridArea='items'>{items}</Box>
|
|
95
|
+
|
|
96
|
+
{pagination && <Box gridArea='afterContent'>{pagination}</Box>}
|
|
97
|
+
</Container>
|
|
98
|
+
</>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
@@ -50,8 +50,8 @@ export function ProductFiltersProLimitChip(props: ProductFiltersProLimitChipProp
|
|
|
50
50
|
onReset={
|
|
51
51
|
activePageSize
|
|
52
52
|
? () => {
|
|
53
|
-
form.
|
|
54
|
-
form.
|
|
53
|
+
form.setValue('pageSize', null)
|
|
54
|
+
form.setValue('currentPage', 1)
|
|
55
55
|
return submit()
|
|
56
56
|
}
|
|
57
57
|
: undefined
|
|
@@ -3,17 +3,18 @@ import { useQuery } from '@graphcommerce/graphql'
|
|
|
3
3
|
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
|
4
4
|
import {
|
|
5
5
|
ActionCard,
|
|
6
|
+
ActionCardAccordion,
|
|
6
7
|
ActionCardItemBase,
|
|
7
8
|
ActionCardListForm,
|
|
8
|
-
|
|
9
|
+
Button,
|
|
9
10
|
} from '@graphcommerce/next-ui'
|
|
10
11
|
import { Trans } from '@lingui/react'
|
|
11
|
-
import { Box, Button } from '@mui/material'
|
|
12
12
|
import { useMemo } from 'react'
|
|
13
13
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
14
14
|
|
|
15
|
-
export type ProductFiltersProLimitSectionProps =
|
|
15
|
+
export type ProductFiltersProLimitSectionProps = Record<string, unknown>
|
|
16
16
|
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
17
18
|
export function ProductFiltersProLimitSection(props: ProductFiltersProLimitSectionProps) {
|
|
18
19
|
const { form } = useProductFiltersPro()
|
|
19
20
|
const { control } = form
|
|
@@ -36,34 +37,36 @@ export function ProductFiltersProLimitSection(props: ProductFiltersProLimitSecti
|
|
|
36
37
|
if (options.length <= 1) return null
|
|
37
38
|
|
|
38
39
|
return (
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
40
|
+
<ActionCardAccordion
|
|
41
|
+
defaultExpanded={!!activePageSize}
|
|
42
|
+
summary={<Trans id='Per page' />}
|
|
43
|
+
details={
|
|
44
|
+
<ActionCardListForm
|
|
45
|
+
sx={{ mb: 2 }}
|
|
46
|
+
render={ActionCard}
|
|
47
|
+
name='pageSize'
|
|
48
|
+
control={control}
|
|
49
|
+
layout='list'
|
|
50
|
+
variant='default'
|
|
51
|
+
size='medium'
|
|
52
|
+
items={options}
|
|
53
|
+
/>
|
|
54
|
+
}
|
|
55
|
+
right={
|
|
56
|
+
activePageSize ? (
|
|
57
|
+
<Button
|
|
58
|
+
variant='inline'
|
|
59
|
+
color='primary'
|
|
60
|
+
onClick={(e) => {
|
|
61
|
+
e.stopPropagation()
|
|
62
|
+
form.setValue('pageSize', null)
|
|
63
|
+
form.setValue('currentPage', 1)
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
<Trans id='Clear' />
|
|
67
|
+
</Button>
|
|
68
|
+
) : undefined
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
68
71
|
)
|
|
69
72
|
}
|
|
@@ -49,8 +49,9 @@ export function ProductFiltersProSortChip(props: ProductListActionSortProps) {
|
|
|
49
49
|
onReset={
|
|
50
50
|
activeSort
|
|
51
51
|
? () => {
|
|
52
|
-
form.
|
|
53
|
-
form.
|
|
52
|
+
form.setValue('sort', null)
|
|
53
|
+
form.setValue('dir', null)
|
|
54
|
+
form.setValue('currentPage', 1)
|
|
54
55
|
return submit()
|
|
55
56
|
}
|
|
56
57
|
: undefined
|
|
@@ -3,13 +3,12 @@ import { useQuery } from '@graphcommerce/graphql'
|
|
|
3
3
|
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
|
4
4
|
import {
|
|
5
5
|
ActionCard,
|
|
6
|
+
ActionCardAccordion,
|
|
6
7
|
ActionCardListForm,
|
|
7
8
|
Button,
|
|
8
9
|
filterNonNullableKeys,
|
|
9
|
-
SectionHeader,
|
|
10
10
|
} from '@graphcommerce/next-ui'
|
|
11
11
|
import { Trans } from '@lingui/react'
|
|
12
|
-
import { Box } from '@mui/material'
|
|
13
12
|
import { useMemo } from 'react'
|
|
14
13
|
import { ProductListSortFragment } from '../ProductListSort/ProductListSort.gql'
|
|
15
14
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
@@ -36,34 +35,35 @@ export function ProductFiltersProSortSection(props: ProductFiltersProSortSection
|
|
|
36
35
|
)
|
|
37
36
|
|
|
38
37
|
return (
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
38
|
+
<ActionCardAccordion
|
|
39
|
+
defaultExpanded={!!activeSort}
|
|
40
|
+
summary={<Trans id='Sort By' />}
|
|
41
|
+
details={
|
|
42
|
+
<ActionCardListForm
|
|
43
|
+
control={control}
|
|
44
|
+
name='sort'
|
|
45
|
+
layout='list'
|
|
46
|
+
variant='default'
|
|
47
|
+
size='medium'
|
|
48
|
+
render={ActionCard}
|
|
49
|
+
items={options}
|
|
50
|
+
/>
|
|
51
|
+
}
|
|
52
|
+
right={
|
|
53
|
+
activeSort ? (
|
|
54
|
+
<Button
|
|
55
|
+
color='primary'
|
|
56
|
+
onClick={(e) => {
|
|
57
|
+
e.stopPropagation()
|
|
58
|
+
form.setValue('sort', null)
|
|
59
|
+
form.setValue('dir', null)
|
|
60
|
+
form.setValue('currentPage', 1)
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
63
|
+
<Trans id='Clear' />
|
|
64
|
+
</Button>
|
|
65
|
+
) : undefined
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
68
|
)
|
|
69
69
|
}
|
|
@@ -2,7 +2,10 @@ export * from './ProductFilterEqualChip'
|
|
|
2
2
|
export * from './ProductFilterRangeChip'
|
|
3
3
|
export * from './ProductFiltersPro'
|
|
4
4
|
export * from './ProductFiltersProAllFiltersChip'
|
|
5
|
+
export * from './ProductFiltersProAllFiltersSidebar'
|
|
5
6
|
export * from './ProductFiltersProChips'
|
|
7
|
+
export * from './ProductFiltersProClearAll'
|
|
8
|
+
export * from './ProductFiltersProLayoutSidebar'
|
|
6
9
|
export * from './ProductFiltersProLimitChip'
|
|
7
10
|
export * from './ProductFiltersProLimitSection'
|
|
8
11
|
export * from './ProductFiltersProSortChip'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback } from 'react'
|
|
2
|
+
import { ProductFilterParams } from '../ProductListItems/filterTypes'
|
|
3
|
+
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
4
|
+
|
|
5
|
+
export function useClearAllFiltersAction() {
|
|
6
|
+
const { form, submit } = useProductFiltersPro()
|
|
7
|
+
const { reset, getValues } = form
|
|
8
|
+
|
|
9
|
+
return useCallback(() => {
|
|
10
|
+
const currentValues = getValues()
|
|
11
|
+
const cleanedFilters: ProductFilterParams['filters'] = Object.fromEntries(
|
|
12
|
+
Object.keys(currentValues.filters).map((key) => [key, null]),
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
reset(
|
|
16
|
+
{
|
|
17
|
+
...currentValues,
|
|
18
|
+
pageSize: null,
|
|
19
|
+
currentPage: 1,
|
|
20
|
+
dir: null,
|
|
21
|
+
sort: null,
|
|
22
|
+
filters: {
|
|
23
|
+
...cleanedFilters,
|
|
24
|
+
category_uid: getValues('filters.category_uid'),
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{ keepSubmitCount: true, keepIsValid: true },
|
|
28
|
+
)
|
|
29
|
+
return submit()
|
|
30
|
+
}, [getValues, reset, submit])
|
|
31
|
+
}
|