@graphcommerce/magento-product 8.0.6-canary.4 → 8.0.6
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 +1 -27
- package/components/AddProductsToCart/AddProductsToCartSnackbar.tsx +3 -2
- package/components/AddProductsToCart/useAddProductsToCartAction.ts +2 -4
- package/components/JsonLdProduct/JsonLdProductOffer.graphql +3 -2
- package/components/JsonLdProduct/ProductPageJsonLd.tsx +6 -4
- package/components/ProductAddToCart/ProductAddToCart.tsx +4 -6
- package/components/ProductFiltersPro/ProductFiltersPro.tsx +6 -13
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +2 -6
- package/components/ProductFiltersPro/ProductFiltersProAllFiltersSidebar.tsx +2 -6
- package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +28 -9
- package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +32 -7
- package/components/ProductListItems/filterTypes.tsx +1 -1
- package/components/ProductListItems/filteredProductList.tsx +1 -1
- package/components/index.ts +0 -2
- package/hooks/useProductListLink.ts +5 -10
- package/package.json +13 -13
- package/components/ProductFiltersPro/ProductFiltersProSortDirectionArrow.tsx +0 -17
- package/components/ProductFiltersPro/useProductFiltersProSort.tsx +0 -74
- package/components/ProductListItems/CategoryDefault.graphql +0 -5
- package/components/ProductListItems/productListApplyCategoryDefaults.ts +0 -28
package/CHANGELOG.md
CHANGED
@@ -1,32 +1,6 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## 8.0.6
|
4
|
-
|
5
|
-
### Patch Changes
|
6
|
-
|
7
|
-
- [#2227](https://github.com/graphcommerce-org/graphcommerce/pull/2227) [`d597719`](https://github.com/graphcommerce-org/graphcommerce/commit/d597719baaabbe079660ac063fd021d871831511) - Added option to change sort order (ASC / DESC) for sort options (Name, price, position etc) on catalog and search pages.
|
8
|
-
([@FrankHarland](https://github.com/FrankHarland))
|
9
|
-
|
10
|
-
## 8.0.6-canary.3
|
11
|
-
|
12
|
-
## 8.0.6-canary.2
|
13
|
-
|
14
|
-
### Patch Changes
|
15
|
-
|
16
|
-
- [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`0767bc4`](https://github.com/graphcommerce-org/graphcommerce/commit/0767bc40f7b596209f24ca4e745ff0441f3275c9) - Upgrade input components to no longer use muiRegister, which improves INP scores
|
17
|
-
([@FrankHarland](https://github.com/FrankHarland))
|
18
|
-
|
19
|
-
- [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`43bd04a`](https://github.com/graphcommerce-org/graphcommerce/commit/43bd04a777c5800cc7e01bee1e123a5aad82f194) - Prevent BillingPage query from rerunning on each mutation
|
20
|
-
([@FrankHarland](https://github.com/FrankHarland))
|
21
|
-
|
22
|
-
## 8.0.6-canary.1
|
23
|
-
|
24
|
-
## 8.0.6-canary.0
|
25
|
-
|
26
|
-
### Patch Changes
|
27
|
-
|
28
|
-
- [#2196](https://github.com/graphcommerce-org/graphcommerce/pull/2196) [`84c50e4`](https://github.com/graphcommerce-org/graphcommerce/commit/84c50e49a1a7f154d4a8f4045c37e773e20283ad) - Allow Lingui to use linguiLocale with country identifiers like `en-us`, it would always load `en` in this case. Introced a new `useLocale` hook to use the correct locale string to use in Intl methods.
|
29
|
-
([@paales](https://github.com/paales))
|
3
|
+
## 8.0.6
|
30
4
|
|
31
5
|
## 8.0.5
|
32
6
|
|
@@ -9,9 +9,9 @@ import {
|
|
9
9
|
MessageSnackbar,
|
10
10
|
MessageSnackbarProps,
|
11
11
|
nonNullable,
|
12
|
-
useLocale,
|
13
12
|
} from '@graphcommerce/next-ui'
|
14
13
|
import { Trans } from '@lingui/react'
|
14
|
+
import { useRouter } from 'next/router'
|
15
15
|
import { useMemo } from 'react'
|
16
16
|
import { findAddedItems } from './findAddedItems'
|
17
17
|
import { toUserErrors } from './toUserErrors'
|
@@ -26,8 +26,9 @@ export function AddProductsToCartSnackbar(props: AddProductsToCartSnackbarProps)
|
|
26
26
|
const { errorSnackbar, successSnackbar } = props
|
27
27
|
const { error, data, redirect, control, submittedVariables } = useFormAddProductsToCart()
|
28
28
|
const formState = useFormState({ control })
|
29
|
+
const { locale } = useRouter()
|
29
30
|
|
30
|
-
const formatter = new Intl.ListFormat(
|
31
|
+
const formatter = new Intl.ListFormat(locale, { style: 'long', type: 'conjunction' })
|
31
32
|
|
32
33
|
const userErrors = toUserErrors(data)
|
33
34
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { useFormState } from '@graphcommerce/ecommerce-ui'
|
2
2
|
import { useEventCallback } from '@mui/material'
|
3
|
-
import {
|
3
|
+
import { useEffect, useState } from 'react'
|
4
4
|
import { UseAddProductsToCartActionFragment } from './UseAddProductsToCartAction.gql'
|
5
5
|
import { toUserErrors } from './toUserErrors'
|
6
6
|
import { AddToCartItemSelector, useFormAddProductsToCart } from './useFormAddProductsToCart'
|
@@ -69,9 +69,7 @@ export function useAddProductsToCartAction(
|
|
69
69
|
if (!sku) console.warn(`You must provide a 'sku' to useAddProductsToCartAction`)
|
70
70
|
}
|
71
71
|
setValue(`cartItems.${index}.sku`, sku ?? '')
|
72
|
-
|
73
|
-
onClickIncoming?.(e)
|
74
|
-
})
|
72
|
+
onClickIncoming?.(e)
|
75
73
|
}),
|
76
74
|
onMouseDown: useEventCallback((e) => e.stopPropagation()),
|
77
75
|
showSuccess,
|
@@ -1,10 +1,12 @@
|
|
1
1
|
import { JsonLd } from '@graphcommerce/next-ui'
|
2
2
|
import { JsonLdProductFragment } from './JsonLdProduct.gql'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
type ProductPageJsonLdProps<T extends { '@type': string }> = {
|
5
|
+
product: JsonLdProductFragment
|
6
|
+
render: (product: JsonLdProductFragment) => T & { '@context': 'https://schema.org' }
|
7
|
+
}
|
8
|
+
|
9
|
+
export function ProductPageJsonLd<T extends { '@type': string }>(props: ProductPageJsonLdProps<T>) {
|
8
10
|
const { product, render } = props
|
9
11
|
return <JsonLd<T> item={render(product)} />
|
10
12
|
}
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import { NumberFieldElement } from '@graphcommerce/ecommerce-ui'
|
2
1
|
import type { ProductInterface } from '@graphcommerce/graphql-mesh'
|
3
2
|
import { ApolloCartErrorAlert, useFormGqlMutationCart } from '@graphcommerce/magento-cart'
|
4
3
|
import { Money, MoneyProps } from '@graphcommerce/magento-store'
|
5
4
|
import {
|
6
5
|
Button,
|
7
6
|
MessageSnackbar,
|
7
|
+
TextInputNumber,
|
8
8
|
iconChevronRight,
|
9
9
|
IconSvg,
|
10
10
|
extendableComponent,
|
@@ -40,7 +40,7 @@ export function ProductAddToCart(
|
|
40
40
|
defaultValues: { ...variables },
|
41
41
|
})
|
42
42
|
|
43
|
-
const { handleSubmit, formState, error,
|
43
|
+
const { handleSubmit, formState, error, muiRegister, required, data } = form
|
44
44
|
const submitHandler = handleSubmit(() => {})
|
45
45
|
|
46
46
|
return (
|
@@ -58,17 +58,15 @@ export function ProductAddToCart(
|
|
58
58
|
<Money {...price} />
|
59
59
|
</Typography>
|
60
60
|
|
61
|
-
<
|
61
|
+
<TextInputNumber
|
62
62
|
variant='outlined'
|
63
63
|
error={formState.isSubmitted && !!formState.errors.quantity}
|
64
64
|
required={required.quantity}
|
65
65
|
inputProps={{ min: 1 }}
|
66
|
-
|
67
|
-
rules={{ required: required.quantity }}
|
66
|
+
{...muiRegister('quantity', { required: required.quantity })}
|
68
67
|
helperText={formState.isSubmitted && formState.errors.quantity?.message}
|
69
68
|
disabled={formState.isSubmitting}
|
70
69
|
size='small'
|
71
|
-
control={control}
|
72
70
|
/>
|
73
71
|
{children}
|
74
72
|
<Box
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import { useForm, UseFormProps, UseFormReturn } from '@graphcommerce/ecommerce-ui'
|
2
2
|
import { useMemoObject } from '@graphcommerce/next-ui'
|
3
3
|
import { useEventCallback } from '@mui/material'
|
4
|
-
import { useRouter } from 'next/router'
|
5
4
|
import React, { BaseSyntheticEvent, createContext, useContext, useMemo } from 'react'
|
6
|
-
import {
|
5
|
+
import { useProductListLinkReplace } from '../../hooks/useProductListLinkReplace'
|
7
6
|
import { ProductListFiltersFragment } from '../ProductListFilters/ProductListFilters.gql'
|
8
7
|
import {
|
9
8
|
ProductFilterParams,
|
10
9
|
ProductListParams,
|
11
10
|
toFilterParams,
|
11
|
+
toProductListParams,
|
12
12
|
} from '../ProductListItems/filterTypes'
|
13
13
|
|
14
14
|
type DataProps = {
|
@@ -50,18 +50,11 @@ export function ProductFiltersPro(props: FilterFormProviderProps) {
|
|
50
50
|
const defaultValues = useMemoObject(toFilterParams(params))
|
51
51
|
const form = useForm<ProductFilterParams>({ defaultValues, ...formProps })
|
52
52
|
|
53
|
-
const
|
54
|
-
|
53
|
+
const push = useProductListLinkReplace({ scroll: false })
|
55
54
|
const submit = useEventCallback(
|
56
|
-
form.handleSubmit(async (formValues) =>
|
57
|
-
|
58
|
-
|
59
|
-
const path = productListLinkFromFilter({ ...formValues, currentPage: 1 })
|
60
|
-
|
61
|
-
if (router.asPath === path) return false
|
62
|
-
if (comingFromURLWithoutFilters) return router.push(path, path)
|
63
|
-
return router.replace(path, path)
|
64
|
-
}),
|
55
|
+
form.handleSubmit(async (formValues) =>
|
56
|
+
push({ ...toProductListParams(formValues), currentPage: 1 }),
|
57
|
+
),
|
65
58
|
)
|
66
59
|
|
67
60
|
const filterFormContext: FilterFormContextProps = useMemo(
|
@@ -29,7 +29,7 @@ const defaultRenderer = {
|
|
29
29
|
}
|
30
30
|
|
31
31
|
export function ProductFiltersProAllFiltersChip(props: ProductFiltersProAllFiltersChipProps) {
|
32
|
-
const { sort_fields, total_count, renderer,
|
32
|
+
const { sort_fields, total_count, renderer, ...rest } = props
|
33
33
|
|
34
34
|
const { submit, params, aggregations, appliedAggregations } = useProductFiltersPro()
|
35
35
|
const { sort } = params
|
@@ -59,11 +59,7 @@ export function ProductFiltersProAllFiltersChip(props: ProductFiltersProAllFilte
|
|
59
59
|
>
|
60
60
|
{() => (
|
61
61
|
<>
|
62
|
-
<ProductFiltersProSortSection
|
63
|
-
sort_fields={sort_fields}
|
64
|
-
total_count={total_count}
|
65
|
-
category={category}
|
66
|
-
/>
|
62
|
+
<ProductFiltersProSortSection sort_fields={sort_fields} total_count={total_count} />
|
67
63
|
<ProductFiltersProLimitSection />
|
68
64
|
<ProductFiltersProAggregations renderer={{ ...defaultRenderer, ...renderer }} />
|
69
65
|
</>
|
@@ -20,15 +20,11 @@ const defaultRenderer = {
|
|
20
20
|
}
|
21
21
|
|
22
22
|
export function ProductFiltersProAllFiltersSidebar(props: ProductFiltersProAllFiltersSidebarProps) {
|
23
|
-
const { sort_fields, total_count, renderer, sx = []
|
23
|
+
const { sort_fields, total_count, renderer, sx = [] } = props
|
24
24
|
|
25
25
|
return (
|
26
26
|
<Box sx={[{ display: { xs: 'none', md: 'grid' } }, ...(Array.isArray(sx) ? sx : [sx])]}>
|
27
|
-
<ProductFiltersProSortSection
|
28
|
-
sort_fields={sort_fields}
|
29
|
-
total_count={total_count}
|
30
|
-
category={category}
|
31
|
-
/>
|
27
|
+
<ProductFiltersProSortSection sort_fields={sort_fields} total_count={total_count} />
|
32
28
|
<ProductFiltersProLimitSection />
|
33
29
|
<ProductFiltersProAggregations renderer={{ ...defaultRenderer, ...renderer }} />
|
34
30
|
</Box>
|
@@ -1,34 +1,53 @@
|
|
1
|
+
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
2
|
+
import { useQuery } from '@graphcommerce/graphql'
|
3
|
+
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
1
4
|
import {
|
2
5
|
ActionCard,
|
3
6
|
ActionCardListForm,
|
4
7
|
ChipOverlayOrPopper,
|
5
8
|
ChipOverlayOrPopperProps,
|
9
|
+
filterNonNullableKeys,
|
6
10
|
} from '@graphcommerce/next-ui'
|
7
11
|
import { Trans } from '@lingui/react'
|
12
|
+
import { useMemo } from 'react'
|
13
|
+
import { ProductListSortFragment } from '../ProductListSort/ProductListSort.gql'
|
8
14
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
9
|
-
import { UseProductFiltersProSortProps, useProductFiltersProSort } from './useProductFiltersProSort'
|
10
15
|
|
11
|
-
export type ProductListActionSortProps =
|
16
|
+
export type ProductListActionSortProps = ProductListSortFragment &
|
12
17
|
Omit<
|
13
18
|
ChipOverlayOrPopperProps,
|
14
19
|
'label' | 'selected' | 'selectedLabel' | 'onApply' | 'onReset' | 'onClose' | 'children'
|
15
20
|
>
|
16
21
|
|
17
22
|
export function ProductFiltersProSortChip(props: ProductListActionSortProps) {
|
18
|
-
const { sort_fields, chipProps,
|
19
|
-
const {
|
20
|
-
const {
|
23
|
+
const { sort_fields, chipProps, ...rest } = props
|
24
|
+
const { params, form, submit } = useProductFiltersPro()
|
25
|
+
const { control } = form
|
26
|
+
const activeSort = useWatch({ control, name: 'sort' })
|
27
|
+
|
28
|
+
const { data: storeConfigQuery } = useQuery(StoreConfigDocument)
|
29
|
+
const defaultSort = storeConfigQuery?.storeConfig?.catalog_default_sort_by
|
30
|
+
|
31
|
+
const options = useMemo(
|
32
|
+
() =>
|
33
|
+
filterNonNullableKeys(sort_fields?.options, ['value', 'label']).map((option) => ({
|
34
|
+
...option,
|
35
|
+
value: option.value === defaultSort ? null : option.value,
|
36
|
+
title: option.label,
|
37
|
+
})),
|
38
|
+
[defaultSort, sort_fields?.options],
|
39
|
+
)
|
21
40
|
|
22
41
|
return (
|
23
42
|
<ChipOverlayOrPopper
|
24
43
|
{...rest}
|
25
44
|
overlayProps={{ sizeSm: 'minimal', sizeMd: 'minimal', ...rest.overlayProps }}
|
26
45
|
label={<Trans id='Sort By' />}
|
27
|
-
selected={
|
28
|
-
selectedLabel={
|
46
|
+
selected={Boolean(params.sort)}
|
47
|
+
selectedLabel={options.find((option) => option.value === params.sort)?.label}
|
29
48
|
onApply={submit}
|
30
49
|
onReset={
|
31
|
-
|
50
|
+
activeSort
|
32
51
|
? () => {
|
33
52
|
form.setValue('sort', null)
|
34
53
|
form.setValue('dir', null)
|
@@ -41,7 +60,7 @@ export function ProductFiltersProSortChip(props: ProductListActionSortProps) {
|
|
41
60
|
>
|
42
61
|
{() => (
|
43
62
|
<ActionCardListForm
|
44
|
-
control={
|
63
|
+
control={control}
|
45
64
|
name='sort'
|
46
65
|
layout='list'
|
47
66
|
variant='default'
|
@@ -1,21 +1,46 @@
|
|
1
|
-
import {
|
1
|
+
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
2
|
+
import { useQuery } from '@graphcommerce/graphql'
|
3
|
+
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
4
|
+
import {
|
5
|
+
ActionCard,
|
6
|
+
ActionCardAccordion,
|
7
|
+
ActionCardListForm,
|
8
|
+
Button,
|
9
|
+
filterNonNullableKeys,
|
10
|
+
} from '@graphcommerce/next-ui'
|
2
11
|
import { Trans } from '@lingui/react'
|
12
|
+
import { useMemo } from 'react'
|
13
|
+
import { ProductListSortFragment } from '../ProductListSort/ProductListSort.gql'
|
3
14
|
import { useProductFiltersPro } from './ProductFiltersPro'
|
4
|
-
import { UseProductFiltersProSortProps, useProductFiltersProSort } from './useProductFiltersProSort'
|
5
15
|
|
6
|
-
export type ProductFiltersProSortSectionProps =
|
16
|
+
export type ProductFiltersProSortSectionProps = ProductListSortFragment
|
7
17
|
|
8
18
|
export function ProductFiltersProSortSection(props: ProductFiltersProSortSectionProps) {
|
19
|
+
const { sort_fields } = props
|
9
20
|
const { form } = useProductFiltersPro()
|
10
|
-
const {
|
21
|
+
const { control } = form
|
22
|
+
const activeSort = useWatch({ control, name: 'sort' })
|
23
|
+
|
24
|
+
const { data: storeConfigQuery } = useQuery(StoreConfigDocument)
|
25
|
+
const defaultSort = storeConfigQuery?.storeConfig?.catalog_default_sort_by
|
26
|
+
|
27
|
+
const options = useMemo(
|
28
|
+
() =>
|
29
|
+
filterNonNullableKeys(sort_fields?.options, ['value', 'label']).map((option) => ({
|
30
|
+
...option,
|
31
|
+
value: option.value === defaultSort ? null : option.value,
|
32
|
+
title: option.label,
|
33
|
+
})),
|
34
|
+
[defaultSort, sort_fields?.options],
|
35
|
+
)
|
11
36
|
|
12
37
|
return (
|
13
38
|
<ActionCardAccordion
|
14
|
-
defaultExpanded={
|
39
|
+
defaultExpanded={!!activeSort}
|
15
40
|
summary={<Trans id='Sort By' />}
|
16
41
|
details={
|
17
42
|
<ActionCardListForm
|
18
|
-
control={
|
43
|
+
control={control}
|
19
44
|
name='sort'
|
20
45
|
layout='list'
|
21
46
|
variant='default'
|
@@ -25,7 +50,7 @@ export function ProductFiltersProSortSection(props: ProductFiltersProSortSection
|
|
25
50
|
/>
|
26
51
|
}
|
27
52
|
right={
|
28
|
-
|
53
|
+
activeSort ? (
|
29
54
|
<Button
|
30
55
|
color='primary'
|
31
56
|
onClick={(e) => {
|
@@ -31,7 +31,7 @@ export type ProductFilterParams = {
|
|
31
31
|
|
32
32
|
export function toFilterParams(params: ProductListParams): ProductFilterParams {
|
33
33
|
const [sortKey] = Object.keys(params.sort) as [keyof ProductAttributeSortInput]
|
34
|
-
const dir = params.sort[sortKey]
|
34
|
+
const dir = params.sort[sortKey] as SortEnum | undefined
|
35
35
|
|
36
36
|
return {
|
37
37
|
...params,
|
@@ -35,7 +35,7 @@ export function parseParams(
|
|
35
35
|
}
|
36
36
|
if (param === 'dir') {
|
37
37
|
const [sortBy] = Object.keys(categoryVariables.sort)
|
38
|
-
if (sortBy) categoryVariables.sort[sortBy] = value
|
38
|
+
if (sortBy) categoryVariables.sort[sortBy] = value as SortEnum
|
39
39
|
return undefined
|
40
40
|
}
|
41
41
|
|
package/components/index.ts
CHANGED
@@ -13,8 +13,6 @@ export * from './ProductListItems/filterTypes'
|
|
13
13
|
export * from './ProductListItems/getFilterTypes'
|
14
14
|
export * from './ProductListItems/ProductListItems.gql'
|
15
15
|
export * from './ProductListItems/ProductListItemsBase'
|
16
|
-
export * from './ProductListItems/productListApplyCategoryDefaults'
|
17
|
-
export * from './ProductListItems/CategoryDefault.gql'
|
18
16
|
export * from './ProductListItems/ProductListParamsProvider'
|
19
17
|
export * from './ProductListItems/renderer'
|
20
18
|
export * from './ProductListLink/ProductListLink'
|
@@ -2,13 +2,11 @@ import {
|
|
2
2
|
isFilterTypeEqual,
|
3
3
|
isFilterTypeMatch,
|
4
4
|
isFilterTypeRange,
|
5
|
-
ProductFilterParams,
|
6
5
|
ProductListParams,
|
7
|
-
toFilterParams,
|
8
6
|
} from '../components/ProductListItems/filterTypes'
|
9
7
|
|
10
|
-
export function
|
11
|
-
const { url, sort,
|
8
|
+
export function productListLink(props: ProductListParams): string {
|
9
|
+
const { url, sort, currentPage, pageSize, filters: incoming } = props
|
12
10
|
const isSearch = url.startsWith('search')
|
13
11
|
const filters = isSearch ? incoming : { ...incoming, category_uid: undefined }
|
14
12
|
const uid = incoming?.category_uid?.eq || incoming?.category_uid?.in?.[0]
|
@@ -21,8 +19,9 @@ export function productListLinkFromFilter(props: ProductFilterParams): string {
|
|
21
19
|
|
22
20
|
// todo(paales): How should the URL look like with multiple sorts?
|
23
21
|
// Something like: /sort/position,price/dir/asc,asc
|
24
|
-
|
25
|
-
if (
|
22
|
+
const [sortBy] = Object.keys(sort)
|
23
|
+
if (sort && sortBy) query += `/sort/${sortBy}`
|
24
|
+
if (sort && sortBy && sort[sortBy] && sort[sortBy] === 'DESC') query += `/dir/desc`
|
26
25
|
if (pageSize) query += `/page-size/${pageSize}`
|
27
26
|
|
28
27
|
// Apply filters
|
@@ -43,10 +42,6 @@ export function productListLinkFromFilter(props: ProductFilterParams): string {
|
|
43
42
|
return query ? `/${url}${paginateSort}/q${query}` : `/${url}${paginateSort}`
|
44
43
|
}
|
45
44
|
|
46
|
-
export function productListLink(props: ProductListParams): string {
|
47
|
-
return productListLinkFromFilter(toFilterParams(props))
|
48
|
-
}
|
49
|
-
|
50
45
|
export function useProductListLink(props: ProductListParams): string {
|
51
46
|
return productListLink({ ...props, url: `${props.url}` })
|
52
47
|
}
|
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": "8.0.6
|
5
|
+
"version": "8.0.6",
|
6
6
|
"sideEffects": false,
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
8
8
|
"eslintConfig": {
|
@@ -18,18 +18,18 @@
|
|
18
18
|
"typescript": "5.3.3"
|
19
19
|
},
|
20
20
|
"peerDependencies": {
|
21
|
-
"@graphcommerce/ecommerce-ui": "^8.0.6
|
22
|
-
"@graphcommerce/eslint-config-pwa": "^8.0.6
|
23
|
-
"@graphcommerce/framer-next-pages": "^8.0.6
|
24
|
-
"@graphcommerce/framer-scroller": "^8.0.6
|
25
|
-
"@graphcommerce/graphql": "^8.0.6
|
26
|
-
"@graphcommerce/graphql-mesh": "^8.0.6
|
27
|
-
"@graphcommerce/image": "^8.0.6
|
28
|
-
"@graphcommerce/magento-cart": "^8.0.6
|
29
|
-
"@graphcommerce/magento-store": "^8.0.6
|
30
|
-
"@graphcommerce/next-ui": "^8.0.6
|
31
|
-
"@graphcommerce/prettier-config-pwa": "^8.0.6
|
32
|
-
"@graphcommerce/typescript-config-pwa": "^8.0.6
|
21
|
+
"@graphcommerce/ecommerce-ui": "^8.0.6",
|
22
|
+
"@graphcommerce/eslint-config-pwa": "^8.0.6",
|
23
|
+
"@graphcommerce/framer-next-pages": "^8.0.6",
|
24
|
+
"@graphcommerce/framer-scroller": "^8.0.6",
|
25
|
+
"@graphcommerce/graphql": "^8.0.6",
|
26
|
+
"@graphcommerce/graphql-mesh": "^8.0.6",
|
27
|
+
"@graphcommerce/image": "^8.0.6",
|
28
|
+
"@graphcommerce/magento-cart": "^8.0.6",
|
29
|
+
"@graphcommerce/magento-store": "^8.0.6",
|
30
|
+
"@graphcommerce/next-ui": "^8.0.6",
|
31
|
+
"@graphcommerce/prettier-config-pwa": "^8.0.6",
|
32
|
+
"@graphcommerce/typescript-config-pwa": "^8.0.6",
|
33
33
|
"@lingui/core": "^4.2.1",
|
34
34
|
"@lingui/macro": "^4.2.1",
|
35
35
|
"@lingui/react": "^4.2.1",
|
@@ -1,17 +0,0 @@
|
|
1
|
-
import { SortEnum } from '@graphcommerce/graphql-mesh'
|
2
|
-
import { IconSvg } from '@graphcommerce/next-ui'
|
3
|
-
import * as IconArrowDown from '@graphcommerce/next-ui/icons/arrow-down.svg'
|
4
|
-
import * as IconArrowUp from '@graphcommerce/next-ui/icons/arrow-up.svg'
|
5
|
-
|
6
|
-
type Props = {
|
7
|
-
sortDirection: SortEnum | null
|
8
|
-
}
|
9
|
-
|
10
|
-
export function ProductFiltersProSortDirectionArrow({ sortDirection }: Props) {
|
11
|
-
return (
|
12
|
-
<IconSvg
|
13
|
-
src={sortDirection === 'ASC' || sortDirection === null ? IconArrowUp : IconArrowDown}
|
14
|
-
sx={{ display: 'flex' }}
|
15
|
-
/>
|
16
|
-
)
|
17
|
-
}
|
@@ -1,74 +0,0 @@
|
|
1
|
-
import { useWatch } from '@graphcommerce/ecommerce-ui'
|
2
|
-
import { useQuery } from '@graphcommerce/graphql'
|
3
|
-
import { StoreConfigDocument } from '@graphcommerce/magento-store'
|
4
|
-
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
|
5
|
-
import { i18n } from '@lingui/core'
|
6
|
-
import { useMemo } from 'react'
|
7
|
-
import { CategoryDefaultFragment } from '../ProductListItems/CategoryDefault.gql'
|
8
|
-
import { ProductFilterParams } from '../ProductListItems/filterTypes'
|
9
|
-
import { ProductListSortFragment } from '../ProductListSort'
|
10
|
-
import { useProductFiltersPro } from './ProductFiltersPro'
|
11
|
-
import type { ProductListActionSortProps } from './ProductFiltersProSortChip'
|
12
|
-
import { ProductFiltersProSortDirectionArrow } from './ProductFiltersProSortDirectionArrow'
|
13
|
-
|
14
|
-
const exclude = ['relevance', 'position']
|
15
|
-
|
16
|
-
export type UseProductFiltersProSortProps = ProductListSortFragment & {
|
17
|
-
category?: CategoryDefaultFragment
|
18
|
-
}
|
19
|
-
|
20
|
-
export function useProductFiltersProSort(props: ProductListActionSortProps) {
|
21
|
-
const { sort_fields, category } = props
|
22
|
-
|
23
|
-
const { params, form } = useProductFiltersPro()
|
24
|
-
const { control, setValue } = form
|
25
|
-
|
26
|
-
const sortFields = useMemo(
|
27
|
-
() =>
|
28
|
-
filterNonNullableKeys(sort_fields?.options).map((o) =>
|
29
|
-
!category?.uid && o.value === 'position'
|
30
|
-
? { value: 'relevance', label: i18n._('Relevance') }
|
31
|
-
: o,
|
32
|
-
),
|
33
|
-
[category?.uid, sort_fields?.options],
|
34
|
-
)
|
35
|
-
const availableSortBy = category?.available_sort_by ?? sortFields.map((o) => o.value)
|
36
|
-
|
37
|
-
const conf = useQuery(StoreConfigDocument).data?.storeConfig
|
38
|
-
const defaultSortBy = (
|
39
|
-
category ? category.default_sort_by ?? conf?.catalog_default_sort_by ?? 'position' : 'relevance'
|
40
|
-
) as ProductFilterParams['sort']
|
41
|
-
|
42
|
-
const formSort = useWatch({ control, name: 'sort' })
|
43
|
-
const formDirection = useWatch({ control, name: 'dir' })
|
44
|
-
const showReset = Boolean(formSort !== defaultSortBy || formDirection === 'DESC')
|
45
|
-
const selected = Boolean(params.sort && (params.sort !== defaultSortBy || params.dir === 'DESC'))
|
46
|
-
|
47
|
-
const options = useMemo(
|
48
|
-
() =>
|
49
|
-
sortFields
|
50
|
-
.filter((o) => availableSortBy.includes(o.value))
|
51
|
-
.map((option) => {
|
52
|
-
const value = option.value === defaultSortBy ? null : option.value
|
53
|
-
const showSort = formSort === value && !exclude.includes(option.value)
|
54
|
-
|
55
|
-
return {
|
56
|
-
...option,
|
57
|
-
value,
|
58
|
-
title: option.label,
|
59
|
-
...(showSort && {
|
60
|
-
onClick: () => setValue('dir', formDirection === 'DESC' ? null : 'DESC'),
|
61
|
-
price: <ProductFiltersProSortDirectionArrow sortDirection={formDirection} />,
|
62
|
-
}),
|
63
|
-
}
|
64
|
-
}),
|
65
|
-
[sortFields, availableSortBy, defaultSortBy, formSort, formDirection, setValue],
|
66
|
-
)
|
67
|
-
|
68
|
-
return {
|
69
|
-
options,
|
70
|
-
selected,
|
71
|
-
showReset,
|
72
|
-
selectedLabel: options.find((option) => option.value === params.sort)?.label,
|
73
|
-
}
|
74
|
-
}
|
@@ -1,28 +0,0 @@
|
|
1
|
-
import { StoreConfigQuery } from '@graphcommerce/magento-store'
|
2
|
-
import { CategoryDefaultFragment } from './CategoryDefault.gql'
|
3
|
-
import { ProductListParams } from './filterTypes'
|
4
|
-
import { cloneDeep } from '@graphcommerce/graphql'
|
5
|
-
|
6
|
-
export async function productListApplyCategoryDefaults(
|
7
|
-
params: ProductListParams | undefined,
|
8
|
-
conf: StoreConfigQuery,
|
9
|
-
category: Promise<CategoryDefaultFragment | null | undefined>,
|
10
|
-
) {
|
11
|
-
if (!params) return params
|
12
|
-
|
13
|
-
const newParams = cloneDeep(params)
|
14
|
-
if (!newParams.pageSize) newParams.pageSize = conf.storeConfig?.grid_per_page ?? 12
|
15
|
-
|
16
|
-
if (Object.keys(params.sort).length === 0) {
|
17
|
-
const categorySort = (await category)?.default_sort_by as keyof ProductListParams['sort']
|
18
|
-
const defaultSort = conf.storeConfig?.catalog_default_sort_by as keyof ProductListParams['sort']
|
19
|
-
if (categorySort) newParams.sort = { [categorySort]: 'ASC' }
|
20
|
-
else if (defaultSort) newParams.sort = { [defaultSort]: 'ASC' }
|
21
|
-
}
|
22
|
-
|
23
|
-
if (!newParams.filters.category_uid?.in?.[0]) {
|
24
|
-
newParams.filters.category_uid = { eq: (await category)?.uid }
|
25
|
-
}
|
26
|
-
|
27
|
-
return newParams
|
28
|
-
}
|