@graphcommerce/magento-product 6.0.2-canary.9 → 6.1.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 +58 -0
- package/components/AddProductsToCart/AddProductsToCartForm.tsx +24 -3
- package/components/ProductFiltersPro/PriceSlider.tsx +1 -1
- package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +7 -3
- package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +8 -5
- package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +3 -1
- package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +2 -1
- package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +23 -23
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +19 -15
- package/components/ProductFiltersPro/activeAggregations.ts +25 -0
- package/components/ProductFiltersPro/applyAggregationCount.ts +40 -0
- package/components/ProductList/ProductList.graphql +1 -0
- package/components/ProductListFilters/FilterCheckboxType.tsx +1 -1
- package/components/ProductListFilters/ProductListFilters.graphql +1 -1
- package/components/ProductSpecs/ProductSpecs.tsx +1 -1
- package/package.json +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 6.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1890](https://github.com/graphcommerce-org/graphcommerce/pull/1890) [`f88727915`](https://github.com/graphcommerce-org/graphcommerce/commit/f88727915998690b34d35c7eb5b2af3ca154da3d) - Aggregation options (filters) now show a relevant count when applying filters and hide the count when it doesn't make sense. ([@paales](https://github.com/paales))
|
|
8
|
+
|
|
9
|
+
- [#1877](https://github.com/graphcommerce-org/graphcommerce/pull/1877) [`27cd09247`](https://github.com/graphcommerce-org/graphcommerce/commit/27cd0924751a1ed2d1043e09600c039df76bad45) - Fetching core product page and and related+upsells in parallel so Magento doesn't choke on the query complexity limit. ([@paales](https://github.com/paales))
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#1888](https://github.com/graphcommerce-org/graphcommerce/pull/1888) [`5460925a7`](https://github.com/graphcommerce-org/graphcommerce/commit/5460925a7f8bd0b8a871ed77098bec3a490fa8f2) - Filtering on category_uid wouldn't work on search results page ([@paales](https://github.com/paales))
|
|
14
|
+
|
|
15
|
+
- [#1888](https://github.com/graphcommerce-org/graphcommerce/pull/1888) [`47429b293`](https://github.com/graphcommerce-org/graphcommerce/commit/47429b293f37b3977a862a36cff4da6956c44a4f) - When filtering on a paginated page it would not reset the currentPage to 1 ([@paales](https://github.com/paales))
|
|
16
|
+
|
|
17
|
+
- [#1888](https://github.com/graphcommerce-org/graphcommerce/pull/1888) [`504d74916`](https://github.com/graphcommerce-org/graphcommerce/commit/504d749161959759b78cc5e9dcc7ca61349a0f12) - When the category_uid is filterable it would always show an active filter on all filters ([@paales](https://github.com/paales))
|
|
18
|
+
|
|
19
|
+
- [#1870](https://github.com/graphcommerce-org/graphcommerce/pull/1870) [`fc567a9bd`](https://github.com/graphcommerce-org/graphcommerce/commit/fc567a9bd1b0ef4e8a8996752f279f7b5fd1fe84) - Crosssells will now be preloaded during the addProductsToCart mutation so they are already available in the 'added' overlay, preventing a second scroll. ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
20
|
+
|
|
21
|
+
- [#1894](https://github.com/graphcommerce-org/graphcommerce/pull/1894) [`e08879934`](https://github.com/graphcommerce-org/graphcommerce/commit/e08879934095cee9c8371a4013543864b58c4706) - ProductSpecs would throw an hydration error if there were multiple categories with the same label ([@paales](https://github.com/paales))
|
|
22
|
+
|
|
23
|
+
## 6.0.2-canary.22
|
|
24
|
+
|
|
25
|
+
## 6.0.2-canary.21
|
|
26
|
+
|
|
27
|
+
## 6.0.2-canary.20
|
|
28
|
+
|
|
29
|
+
## 6.0.2-canary.19
|
|
30
|
+
|
|
31
|
+
## 6.0.2-canary.18
|
|
32
|
+
|
|
33
|
+
## 6.0.2-canary.17
|
|
34
|
+
|
|
35
|
+
## 6.0.2-canary.16
|
|
36
|
+
|
|
37
|
+
## 6.0.2-canary.15
|
|
38
|
+
|
|
39
|
+
### Patch Changes
|
|
40
|
+
|
|
41
|
+
- [#1870](https://github.com/graphcommerce-org/graphcommerce/pull/1870) [`fc567a9bd`](https://github.com/graphcommerce-org/graphcommerce/commit/fc567a9bd1b0ef4e8a8996752f279f7b5fd1fe84) - Crosssells will now be preloaded during the addProductsToCart mutation so they are already available in the 'added' overlay, preventing a second scroll. ([@bramvanderholst](https://github.com/bramvanderholst))
|
|
42
|
+
|
|
43
|
+
## 6.0.2-canary.14
|
|
44
|
+
|
|
45
|
+
### Patch Changes
|
|
46
|
+
|
|
47
|
+
- [#1894](https://github.com/graphcommerce-org/graphcommerce/pull/1894) [`e08879934`](https://github.com/graphcommerce-org/graphcommerce/commit/e08879934095cee9c8371a4013543864b58c4706) - ProductSpecs would throw an hydration error if there were multiple categories with the same label ([@paales](https://github.com/paales))
|
|
48
|
+
|
|
49
|
+
## 6.0.2-canary.13
|
|
50
|
+
|
|
51
|
+
## 6.0.2-canary.12
|
|
52
|
+
|
|
53
|
+
## 6.0.2-canary.11
|
|
54
|
+
|
|
55
|
+
### Patch Changes
|
|
56
|
+
|
|
57
|
+
- [#1890](https://github.com/graphcommerce-org/graphcommerce/pull/1890) [`f88727915`](https://github.com/graphcommerce-org/graphcommerce/commit/f88727915998690b34d35c7eb5b2af3ca154da3d) - Aggregation options (filters) now show a relevant count when applying filters and hide the count when it doesn't make sense. ([@paales](https://github.com/paales))
|
|
58
|
+
|
|
59
|
+
## 6.0.2-canary.10
|
|
60
|
+
|
|
3
61
|
## 6.0.2-canary.9
|
|
4
62
|
|
|
5
63
|
## 6.0.2-canary.8
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { UseFormGraphQlOptions } from '@graphcommerce/ecommerce-ui'
|
|
2
|
-
import {
|
|
2
|
+
import { ApolloQueryResult, useApolloClient } from '@graphcommerce/graphql'
|
|
3
|
+
import {
|
|
4
|
+
useFormGqlMutationCart,
|
|
5
|
+
CrosssellsDocument,
|
|
6
|
+
CrosssellsQuery,
|
|
7
|
+
} from '@graphcommerce/magento-cart'
|
|
3
8
|
import { ExtendableComponent } from '@graphcommerce/next-ui'
|
|
4
9
|
import { Box, SxProps, Theme, useThemeProps } from '@mui/material'
|
|
5
10
|
import { useRouter } from 'next/router'
|
|
6
|
-
import { useMemo } from 'react'
|
|
11
|
+
import { useMemo, useRef } from 'react'
|
|
7
12
|
import {
|
|
8
13
|
AddProductsToCartDocument,
|
|
9
14
|
AddProductsToCartMutation,
|
|
@@ -54,6 +59,8 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
|
54
59
|
let { children, redirect, onComplete, sx, errorSnackbar, successSnackbar, ...formProps } =
|
|
55
60
|
useThemeProps({ name, props })
|
|
56
61
|
const router = useRouter()
|
|
62
|
+
const client = useApolloClient()
|
|
63
|
+
const crosssellsQuery = useRef<Promise<ApolloQueryResult<CrosssellsQuery>>>()
|
|
57
64
|
|
|
58
65
|
if (typeof redirect !== 'undefined' && redirect !== 'added' && router.pathname === redirect)
|
|
59
66
|
redirect = undefined
|
|
@@ -69,7 +76,7 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
|
69
76
|
if (variables2 === false) return false
|
|
70
77
|
|
|
71
78
|
const { cartId, cartItems } = variables2
|
|
72
|
-
|
|
79
|
+
const requestData = {
|
|
73
80
|
cartId,
|
|
74
81
|
cartItems: cartItems
|
|
75
82
|
.filter((cartItem) => cartItem.sku)
|
|
@@ -80,6 +87,19 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
|
80
87
|
entered_options: cartItem.entered_options?.filter((option) => option?.value),
|
|
81
88
|
})),
|
|
82
89
|
}
|
|
90
|
+
|
|
91
|
+
const lastItem = requestData.cartItems[requestData.cartItems.length - 1]
|
|
92
|
+
const { sku } = lastItem
|
|
93
|
+
|
|
94
|
+
if (sku && redirect === 'added') {
|
|
95
|
+
// Preload crosssells
|
|
96
|
+
crosssellsQuery.current = client.query({
|
|
97
|
+
query: CrosssellsDocument,
|
|
98
|
+
variables: { pageSize: 1, filters: { sku: { eq: sku } } },
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return requestData
|
|
83
103
|
},
|
|
84
104
|
onComplete: async (result, variables) => {
|
|
85
105
|
await onComplete?.(result, variables)
|
|
@@ -92,6 +112,7 @@ export function AddProductsToCartForm(props: AddProductsToCartFormProps) {
|
|
|
92
112
|
if (toUserErrors(result.data).length || result.errors?.length || !redirect) return
|
|
93
113
|
|
|
94
114
|
if (redirect === 'added') {
|
|
115
|
+
await crosssellsQuery.current
|
|
95
116
|
const method = router.pathname.startsWith('/checkout/added') ? router.replace : router.push
|
|
96
117
|
await method({
|
|
97
118
|
pathname: '/checkout/added',
|
|
@@ -9,7 +9,7 @@ export type PriceSliderProps = {
|
|
|
9
9
|
value: FilterRangeTypeInput | null | undefined
|
|
10
10
|
onChange: (...event: any[]) => void
|
|
11
11
|
sx?: SxProps<Theme>
|
|
12
|
-
options: FilterProps['options']
|
|
12
|
+
options: FilterProps['aggregation']['options']
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const { classes } = extendableComponent('PriceSlider', ['container', 'slider'] as const)
|
|
@@ -15,7 +15,9 @@ import { useProductFiltersPro } from './ProductFiltersPro'
|
|
|
15
15
|
import { FilterProps } from './ProductFiltersProAggregations'
|
|
16
16
|
|
|
17
17
|
export function ProductFilterEqualChip(props: FilterProps) {
|
|
18
|
-
const {
|
|
18
|
+
const { aggregation } = props
|
|
19
|
+
const { attribute_code, label, options } = aggregation
|
|
20
|
+
|
|
19
21
|
const { form, submit, params } = useProductFiltersPro()
|
|
20
22
|
const { control } = form
|
|
21
23
|
const attrCode = attribute_code as keyof ProductAttributeFilterInput
|
|
@@ -35,12 +37,14 @@ export function ProductFilterEqualChip(props: FilterProps) {
|
|
|
35
37
|
|
|
36
38
|
const items = useMemo(
|
|
37
39
|
() =>
|
|
38
|
-
filterNonNullableKeys(options, ['
|
|
40
|
+
filterNonNullableKeys(options, ['label']).map((option) => ({
|
|
39
41
|
...option,
|
|
40
42
|
title: (
|
|
41
43
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
42
44
|
<div>{option.label}</div>
|
|
43
|
-
|
|
45
|
+
{option.count !== null && (
|
|
46
|
+
<Box sx={{ typography: 'caption', color: 'text.disabled' }}>({option.count})</Box>
|
|
47
|
+
)}
|
|
44
48
|
</Box>
|
|
45
49
|
),
|
|
46
50
|
image: attrCode?.toLowerCase().includes('color') && (
|
|
@@ -17,7 +17,8 @@ import { useProductFiltersPro } from './ProductFiltersPro'
|
|
|
17
17
|
import { FilterProps } from './ProductFiltersProAggregations'
|
|
18
18
|
|
|
19
19
|
export function ProductFilterEqualSection(props: FilterProps) {
|
|
20
|
-
const {
|
|
20
|
+
const { aggregation } = props
|
|
21
|
+
const { attribute_code, label, options } = aggregation
|
|
21
22
|
const { form, submit, params } = useProductFiltersPro()
|
|
22
23
|
const { control } = form
|
|
23
24
|
const attrCode = attribute_code as keyof ProductAttributeFilterInput
|
|
@@ -31,14 +32,16 @@ export function ProductFilterEqualSection(props: FilterProps) {
|
|
|
31
32
|
|
|
32
33
|
const items = useMemo(
|
|
33
34
|
() =>
|
|
34
|
-
filterNonNullableKeys(options, ['
|
|
35
|
+
filterNonNullableKeys(options, ['label']).map((option) => ({
|
|
35
36
|
...option,
|
|
36
37
|
title: (
|
|
37
38
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
38
39
|
<Typography sx={{ marginRight: 1 }}>{option.label}</Typography>
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
{option.count !== null && (
|
|
41
|
+
<Typography variant='caption' color='text.disabled'>
|
|
42
|
+
({option.count})
|
|
43
|
+
</Typography>
|
|
44
|
+
)}
|
|
42
45
|
</Box>
|
|
43
46
|
),
|
|
44
47
|
image: attrCode?.toLowerCase().includes('color') && (
|
|
@@ -10,7 +10,9 @@ import { FilterProps } from './ProductFiltersProAggregations'
|
|
|
10
10
|
const { classes } = extendableComponent('FilterRangeType', ['root', 'container', 'slider'] as const)
|
|
11
11
|
|
|
12
12
|
export function ProductFilterRangeChip(props: FilterProps) {
|
|
13
|
-
const {
|
|
13
|
+
const { aggregation } = props
|
|
14
|
+
const { attribute_code, label, options } = aggregation
|
|
15
|
+
|
|
14
16
|
const { form, submit, params } = useProductFiltersPro()
|
|
15
17
|
const { control } = form
|
|
16
18
|
const attrCode = attribute_code as keyof ProductAttributeFilterInput
|
|
@@ -9,7 +9,8 @@ import { useProductFiltersPro } from './ProductFiltersPro'
|
|
|
9
9
|
import { FilterProps } from './ProductFiltersProAggregations'
|
|
10
10
|
|
|
11
11
|
export function ProductFilterRangeSection(props: FilterProps) {
|
|
12
|
-
const {
|
|
12
|
+
const { aggregation } = props
|
|
13
|
+
const { attribute_code, label, options } = aggregation
|
|
13
14
|
|
|
14
15
|
const { form, params } = useProductFiltersPro()
|
|
15
16
|
const { control } = form
|
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
|
|
2
1
|
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
|
3
2
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
3
|
+
import { excludeCategory } from './activeAggregations'
|
|
4
|
+
import { applyAggregationCount } from './applyAggregationCount'
|
|
4
5
|
|
|
5
|
-
export type FilterProps =
|
|
6
|
-
NonNullable<ProductListFiltersFragment['aggregations']>[number]
|
|
7
|
-
|
|
6
|
+
export type FilterProps = {
|
|
7
|
+
aggregation: NonNullable<NonNullable<ProductListFiltersFragment['aggregations']>[number]>
|
|
8
|
+
}
|
|
8
9
|
|
|
9
10
|
export type FilterRenderer = Record<string, React.FC<FilterProps>>
|
|
10
11
|
|
|
11
12
|
export type ProductFiltersProAggregationsProps = {
|
|
12
13
|
filterTypes: Record<string, string | undefined>
|
|
13
14
|
renderer?: FilterRenderer
|
|
15
|
+
appliedAggregations?: ProductListFiltersFragment['aggregations']
|
|
14
16
|
} & ProductListFiltersFragment
|
|
15
17
|
|
|
16
18
|
export function ProductFiltersProAggregations(props: ProductFiltersProAggregationsProps) {
|
|
17
|
-
const { aggregations, filterTypes, renderer } = props
|
|
19
|
+
const { aggregations, appliedAggregations, filterTypes, renderer } = props
|
|
18
20
|
const { params } = useProductFiltersPro()
|
|
19
21
|
|
|
20
22
|
return (
|
|
21
23
|
<>
|
|
22
|
-
{
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const filterType = filterTypes[aggregation.attribute_code]
|
|
29
|
-
if (!filterType) return null
|
|
24
|
+
{excludeCategory(
|
|
25
|
+
applyAggregationCount(aggregations, appliedAggregations, params),
|
|
26
|
+
params,
|
|
27
|
+
).map((aggregation) => {
|
|
28
|
+
const filterType = filterTypes[aggregation.attribute_code]
|
|
29
|
+
if (!filterType) return null
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
return null
|
|
31
|
+
const Component = renderer?.[filterType]
|
|
32
|
+
if (!Component) {
|
|
33
|
+
if (process.env.NODE_ENV === 'development') {
|
|
34
|
+
console.log(
|
|
35
|
+
`The renderer for fitlerType ${filterType} can not be found, please add it to the renderer prop: renderer={{ ${filterType}: (props) => <>MYRenderer</> }}}}`,
|
|
36
|
+
)
|
|
39
37
|
}
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
return <Component key={aggregation.attribute_code} aggregation={aggregation} {...props} />
|
|
42
|
+
})}
|
|
43
43
|
</>
|
|
44
44
|
)
|
|
45
45
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
|
2
1
|
import {
|
|
3
2
|
ChipOverlayOrPopper,
|
|
4
3
|
ChipOverlayOrPopperProps,
|
|
@@ -6,6 +5,8 @@ import {
|
|
|
6
5
|
} from '@graphcommerce/next-ui'
|
|
7
6
|
import { Trans } from '@lingui/react'
|
|
8
7
|
import { Box } from '@mui/material'
|
|
8
|
+
import { activeAggregations } from './activeAggregations'
|
|
9
|
+
import { applyAggregationCount } from './applyAggregationCount'
|
|
9
10
|
import { ProductFilterEqualSection } from './ProductFilterEqualSection'
|
|
10
11
|
import { ProductFilterRangeSection } from './ProductFilterRangeSection'
|
|
11
12
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
|
@@ -26,21 +27,23 @@ type AllFiltersChip = ProductFiltersProAggregationsProps &
|
|
|
26
27
|
>
|
|
27
28
|
|
|
28
29
|
export function ProductFiltersProAllFiltersChip(props: AllFiltersChip) {
|
|
29
|
-
const {
|
|
30
|
+
const {
|
|
31
|
+
filterTypes,
|
|
32
|
+
aggregations,
|
|
33
|
+
appliedAggregations: aggregationsCount,
|
|
34
|
+
sort_fields,
|
|
35
|
+
total_count,
|
|
36
|
+
renderer,
|
|
37
|
+
...rest
|
|
38
|
+
} = props
|
|
30
39
|
|
|
31
40
|
const { form, submit, params } = useProductFiltersPro()
|
|
32
|
-
const {
|
|
41
|
+
const { sort } = params
|
|
33
42
|
|
|
34
|
-
const activeFilters =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})
|
|
39
|
-
.filter(
|
|
40
|
-
({ attribute_code }) =>
|
|
41
|
-
filters[attribute_code]?.from || filters[attribute_code]?.to || filters[attribute_code]?.in,
|
|
42
|
-
)
|
|
43
|
-
.map(({ label }) => label)
|
|
43
|
+
const activeFilters = activeAggregations(
|
|
44
|
+
applyAggregationCount(aggregations, aggregationsCount, params),
|
|
45
|
+
params,
|
|
46
|
+
).map(({ label }) => label)
|
|
44
47
|
|
|
45
48
|
const allFilters = [...activeFilters, sort].filter(Boolean)
|
|
46
49
|
const hasFilters = allFilters.length > 0
|
|
@@ -53,7 +56,7 @@ export function ProductFiltersProAllFiltersChip(props: AllFiltersChip) {
|
|
|
53
56
|
onReset={
|
|
54
57
|
hasFilters
|
|
55
58
|
? () => {
|
|
56
|
-
form.setValue('filters', { category_uid: filters.category_uid })
|
|
59
|
+
form.setValue('filters', { category_uid: params.filters.category_uid })
|
|
57
60
|
form.setValue('currentPage', 1)
|
|
58
61
|
form.setValue('sort', null)
|
|
59
62
|
form.setValue('dir', null)
|
|
@@ -70,10 +73,11 @@ export function ProductFiltersProAllFiltersChip(props: AllFiltersChip) {
|
|
|
70
73
|
>
|
|
71
74
|
{() => (
|
|
72
75
|
<Box sx={(theme) => ({ display: 'grid', rowGap: theme.spacings.sm })}>
|
|
73
|
-
<ProductFiltersProSortSection sort_fields={sort_fields} />
|
|
76
|
+
<ProductFiltersProSortSection sort_fields={sort_fields} total_count={total_count} />
|
|
74
77
|
<ProductFiltersProAggregations
|
|
75
78
|
filterTypes={filterTypes}
|
|
76
79
|
aggregations={aggregations}
|
|
80
|
+
appliedAggregations={aggregationsCount}
|
|
77
81
|
renderer={{
|
|
78
82
|
FilterRangeTypeInput: ProductFilterRangeSection,
|
|
79
83
|
FilterEqualTypeInput: ProductFilterEqualSection,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
|
|
2
|
+
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
|
3
|
+
import { ProductFilterParams } from '../ProductListItems/filterTypes'
|
|
4
|
+
|
|
5
|
+
export function excludeCategory(
|
|
6
|
+
aggregations: ProductListFiltersFragment['aggregations'],
|
|
7
|
+
params: ProductFilterParams,
|
|
8
|
+
) {
|
|
9
|
+
return filterNonNullableKeys(aggregations).filter(({ attribute_code }) => {
|
|
10
|
+
if (params.search !== null) return true
|
|
11
|
+
return attribute_code !== 'category_id' && attribute_code !== 'category_uid'
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function activeAggregations(
|
|
16
|
+
aggregations: ProductListFiltersFragment['aggregations'],
|
|
17
|
+
params: ProductFilterParams,
|
|
18
|
+
) {
|
|
19
|
+
return excludeCategory(aggregations, params).filter(
|
|
20
|
+
({ attribute_code }) =>
|
|
21
|
+
params.filters[attribute_code]?.from ||
|
|
22
|
+
params.filters[attribute_code]?.to ||
|
|
23
|
+
params.filters[attribute_code]?.in,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
|
|
2
|
+
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
|
3
|
+
import { ProductFilterParams } from '../ProductListItems/filterTypes'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Apply aggregation count to aggregation options:
|
|
7
|
+
*
|
|
8
|
+
* - If the filter is applied and there is only one filter applied we can show the count
|
|
9
|
+
* - If the filter is applied and there is more than one filter applied we don't show the count
|
|
10
|
+
* - If the filter is not applied we show the count from the applied aggregation
|
|
11
|
+
*/
|
|
12
|
+
export function applyAggregationCount(
|
|
13
|
+
aggregations: ProductListFiltersFragment['aggregations'],
|
|
14
|
+
appliedAggregations: ProductListFiltersFragment['aggregations'],
|
|
15
|
+
params: ProductFilterParams,
|
|
16
|
+
) {
|
|
17
|
+
const filterCount = Object.keys(params.filters).filter((attribute_code) => {
|
|
18
|
+
if (params.search !== null) return true
|
|
19
|
+
return attribute_code !== 'category_id' && attribute_code !== 'category_uid'
|
|
20
|
+
}).length
|
|
21
|
+
|
|
22
|
+
return filterNonNullableKeys(aggregations).map((aggregation) => {
|
|
23
|
+
const appliedAggregation = appliedAggregations?.find(
|
|
24
|
+
(a) => a?.attribute_code === aggregation?.attribute_code,
|
|
25
|
+
)
|
|
26
|
+
const applied = Boolean(params.filters[aggregation.attribute_code])
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
...aggregation,
|
|
30
|
+
options: filterNonNullableKeys(aggregation?.options)?.map((option) => {
|
|
31
|
+
if (applied && filterCount === 1) return option
|
|
32
|
+
if (applied && filterCount > 1) return { ...option, count: null }
|
|
33
|
+
return {
|
|
34
|
+
...option,
|
|
35
|
+
count: appliedAggregation?.options?.find((o) => o?.value === option?.value)?.count ?? 0,
|
|
36
|
+
}
|
|
37
|
+
}),
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
@@ -12,7 +12,7 @@ export type FilterCheckboxTypeProps = Filter &
|
|
|
12
12
|
Omit<ChipProps<'button'>, 'selected' | 'onDelete' | 'component'> & { sx?: SxProps<Theme> }
|
|
13
13
|
|
|
14
14
|
export function FilterCheckboxType(props: FilterCheckboxTypeProps) {
|
|
15
|
-
const { attribute_code,
|
|
15
|
+
const { attribute_code, label, options, ...chipProps } = props
|
|
16
16
|
const { params } = useProductListParamsContext()
|
|
17
17
|
const currentFilter = params.filters[attribute_code]
|
|
18
18
|
const replaceRoute = useProductListLinkReplace({ scroll: false })
|
|
@@ -47,7 +47,7 @@ export function ProductSpecs(props: ProductSpecsProps) {
|
|
|
47
47
|
<div>{aggregation?.label}</div>
|
|
48
48
|
<Box className={classes.options} sx={{ display: 'grid', gridAutoFlow: 'row' }}>
|
|
49
49
|
{aggregation?.options?.map((option) => (
|
|
50
|
-
<span key={option?.
|
|
50
|
+
<span key={option?.value}>{option?.label === '1' ? 'Yes' : option?.label}</span>
|
|
51
51
|
))}
|
|
52
52
|
</Box>
|
|
53
53
|
</li>
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/magento-product",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "6.0
|
|
5
|
+
"version": "6.1.0",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,20 +12,20 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@graphcommerce/eslint-config-pwa": "6.0
|
|
16
|
-
"@graphcommerce/prettier-config-pwa": "6.0
|
|
17
|
-
"@graphcommerce/typescript-config-pwa": "6.0
|
|
15
|
+
"@graphcommerce/eslint-config-pwa": "6.1.0",
|
|
16
|
+
"@graphcommerce/prettier-config-pwa": "6.1.0",
|
|
17
|
+
"@graphcommerce/typescript-config-pwa": "6.1.0"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@graphcommerce/ecommerce-ui": "6.0
|
|
21
|
-
"@graphcommerce/framer-scroller": "6.0
|
|
22
|
-
"@graphcommerce/framer-next-pages": "6.0
|
|
23
|
-
"@graphcommerce/graphql": "6.0
|
|
24
|
-
"@graphcommerce/graphql-mesh": "6.0
|
|
25
|
-
"@graphcommerce/image": "6.0
|
|
26
|
-
"@graphcommerce/magento-cart": "6.0
|
|
27
|
-
"@graphcommerce/magento-store": "6.0
|
|
28
|
-
"@graphcommerce/next-ui": "6.0
|
|
20
|
+
"@graphcommerce/ecommerce-ui": "6.1.0",
|
|
21
|
+
"@graphcommerce/framer-scroller": "6.1.0",
|
|
22
|
+
"@graphcommerce/framer-next-pages": "6.1.0",
|
|
23
|
+
"@graphcommerce/graphql": "6.1.0",
|
|
24
|
+
"@graphcommerce/graphql-mesh": "6.1.0",
|
|
25
|
+
"@graphcommerce/image": "6.1.0",
|
|
26
|
+
"@graphcommerce/magento-cart": "6.1.0",
|
|
27
|
+
"@graphcommerce/magento-store": "6.1.0",
|
|
28
|
+
"@graphcommerce/next-ui": "6.1.0",
|
|
29
29
|
"schema-dts": "^1.1.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|