@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.
Files changed (62) hide show
  1. package/CHANGELOG.md +235 -1
  2. package/Config.graphqls +12 -2
  3. package/components/AddProductsToCart/AddProductsToCart.graphql +1 -0
  4. package/components/AddProductsToCart/AddProductsToCartError.tsx +2 -3
  5. package/components/AddProductsToCart/AddProductsToCartForm.tsx +1 -2
  6. package/components/AddProductsToCart/AddProductsToCartQuantity.tsx +3 -2
  7. package/components/AddProductsToCart/useAddProductsToCartAction.ts +2 -3
  8. package/components/AddProductsToCart/useFormAddProductsToCart.ts +3 -1
  9. package/components/JsonLdProduct/JsonLdProduct.graphql +1 -1
  10. package/components/JsonLdProduct/ProductPageJsonLd.tsx +12 -0
  11. package/components/JsonLdProduct/index.ts +2 -0
  12. package/components/ProductCustomizable/ProductCustomizable.tsx +4 -5
  13. package/components/ProductFiltersPro/PriceSlider.tsx +7 -2
  14. package/components/ProductFiltersPro/ProductFilterEqualChip.tsx +1 -1
  15. package/components/ProductFiltersPro/ProductFilterEqualSection.tsx +36 -37
  16. package/components/ProductFiltersPro/ProductFilterRangeChip.tsx +1 -1
  17. package/components/ProductFiltersPro/ProductFilterRangeSection.tsx +19 -23
  18. package/components/ProductFiltersPro/ProductFiltersPro.tsx +35 -18
  19. package/components/ProductFiltersPro/ProductFiltersProAggregations.tsx +5 -6
  20. package/components/ProductFiltersPro/ProductFiltersProAllFiltersChip.tsx +20 -43
  21. package/components/ProductFiltersPro/ProductFiltersProAllFiltersSidebar.tsx +32 -0
  22. package/components/ProductFiltersPro/ProductFiltersProClearAll.tsx +48 -0
  23. package/components/ProductFiltersPro/ProductFiltersProLayoutSidebar.tsx +100 -0
  24. package/components/ProductFiltersPro/ProductFiltersProLimitChip.tsx +2 -2
  25. package/components/ProductFiltersPro/ProductFiltersProLimitSection.tsx +35 -32
  26. package/components/ProductFiltersPro/ProductFiltersProSortChip.tsx +3 -2
  27. package/components/ProductFiltersPro/ProductFiltersProSortSection.tsx +31 -31
  28. package/components/ProductFiltersPro/index.ts +3 -0
  29. package/components/ProductFiltersPro/useClearAllFiltersHandler.ts +31 -0
  30. package/components/ProductListCount/ProductListCount.tsx +12 -6
  31. package/components/ProductListFilters/FilterEqualType.tsx +1 -0
  32. package/components/ProductListFilters/FilterRangeType.tsx +1 -0
  33. package/components/ProductListItems/ProductListItemsBase.tsx +58 -38
  34. package/components/ProductListItems/filterTypes.tsx +4 -5
  35. package/components/ProductListLink/ProductListLink.tsx +1 -0
  36. package/components/ProductListPagination/ProductListPagination.tsx +14 -7
  37. package/components/ProductListPrice/ProductListPrice.tsx +1 -1
  38. package/components/ProductListPrice/index.ts +2 -0
  39. package/components/ProductPage/ProductPageAddToCartRow.tsx +3 -2
  40. package/components/ProductPageBreadcrumb/ProductPageBreadcrumb.tsx +2 -2
  41. package/components/ProductPageDescription/ProductPageDescription.graphql +1 -0
  42. package/components/ProductPageDescription/ProductPageDescription.tsx +6 -4
  43. package/components/ProductPageGallery/ProductPageGallery.graphql +1 -0
  44. package/components/ProductPageGallery/ProductPageGallery.tsx +6 -8
  45. package/components/ProductPageMeta/ProductPageMeta.graphql +5 -3
  46. package/components/ProductPageMeta/ProductPageMeta.tsx +18 -21
  47. package/components/ProductPageName/ProductPageName.graphql +4 -0
  48. package/components/ProductPageName/ProductPageName.tsx +10 -0
  49. package/components/ProductPageName/index.ts +1 -0
  50. package/components/ProductPagePrice/ProductPagePrice.graphql +1 -0
  51. package/components/ProductPagePrice/ProductPagePrice.tsx +2 -2
  52. package/components/ProductShortDescription/ProductShortDescription.graphql +1 -0
  53. package/components/ProductShortDescription/ProductShortDescription.tsx +6 -2
  54. package/components/ProductSpecs/ProductSpecs.tsx +7 -2
  55. package/components/index.ts +5 -2
  56. package/hooks/useProductListLink.ts +2 -2
  57. package/hooks/useProductListLinkReplace.ts +2 -2
  58. package/index.ts +1 -0
  59. package/package.json +16 -15
  60. package/components/AddProductsToCart/AddProductsToCartIndex.tsx +0 -3
  61. package/components/ProductFiltersPro/useFilterActions.ts +0 -61
  62. package/components/ProductListItems/ProductListItems.tsx +0 -6
@@ -1,4 +1,4 @@
1
- import { responsiveVal, extendableComponent } from '@graphcommerce/next-ui'
1
+ import { extendableComponent, responsiveVal } from '@graphcommerce/next-ui'
2
2
  import { Trans } from '@lingui/react'
3
3
  import { Box, Divider, SxProps, Theme, Typography } from '@mui/material'
4
4
  import { ProductListCountFragment } from './ProductListCount.gql'
@@ -9,7 +9,9 @@ const { classes, selectors } = extendableComponent('ProductListCount', [
9
9
  'count',
10
10
  ] as const)
11
11
 
12
- export type ProductCountProps = ProductListCountFragment & { sx?: SxProps<Theme> }
12
+ export type ProductCountProps = ProductListCountFragment & {
13
+ sx?: SxProps<Theme>
14
+ }
13
15
 
14
16
  export function ProductListCount(props: ProductCountProps) {
15
17
  const { total_count, sx = [] } = props
@@ -24,17 +26,21 @@ export function ProductListCount(props: ProductCountProps) {
24
26
  columnGap: theme.spacings.xs,
25
27
  maxWidth: '100%',
26
28
  width: responsiveVal(280, 650),
27
- margin: '0 auto',
28
29
  alignItems: 'center',
29
- marginTop: theme.spacings.md,
30
- marginBottom: theme.spacings.md,
30
+ my: theme.spacings.md,
31
+ mx: 'auto',
31
32
  }),
32
33
  ...(Array.isArray(sx) ? sx : [sx]),
33
34
  ]}
34
35
  className={classes.root}
35
36
  >
36
37
  <Divider component='div' className={classes.line} />
37
- <Typography variant='body2' color='text.disabled' className={classes.count}>
38
+ <Typography
39
+ variant='body2'
40
+ color='text.disabled'
41
+ className={classes.count}
42
+ sx={{ lineHeight: 0 }}
43
+ >
38
44
  {total_count === 0 && <Trans id='no products' />}
39
45
  {total_count === 1 && <Trans id='one product' />}
40
46
  {(total_count ?? 0) > 1 && <Trans id='{total_count} products' values={{ total_count }} />}
@@ -3,6 +3,7 @@ import type { FilterEqualTypeInput } from '@graphcommerce/graphql-mesh'
3
3
  import { responsiveVal, extendableComponent, ChipMenu, ChipMenuProps } from '@graphcommerce/next-ui'
4
4
  import {
5
5
  Box,
6
+ // eslint-disable-next-line @typescript-eslint/no-restricted-imports
6
7
  Checkbox,
7
8
  ListItem,
8
9
  ListItemSecondaryAction,
@@ -3,6 +3,7 @@ import type { FilterRangeTypeInput } from '@graphcommerce/graphql-mesh'
3
3
  import { Money } from '@graphcommerce/magento-store'
4
4
  import { ChipMenu, ChipMenuProps, extendableComponent } from '@graphcommerce/next-ui'
5
5
  import { Trans } from '@lingui/react'
6
+ // eslint-disable-next-line @typescript-eslint/no-restricted-imports
6
7
  import { Box, Slider } from '@mui/material'
7
8
  import React, { useEffect } from 'react'
8
9
  import { useProductListLinkReplace } from '../../hooks/useProductListLinkReplace'
@@ -1,9 +1,14 @@
1
- import { RenderType, responsiveVal } from '@graphcommerce/next-ui'
1
+ import { RenderType, extendableComponent, responsiveVal } from '@graphcommerce/next-ui'
2
2
  import { Box, BoxProps } from '@mui/material'
3
3
  import { ProductListItemFragment } from '../../Api/ProductListItem.gql'
4
+ import { AddProductsToCartForm } from '../AddProductsToCart'
4
5
  import { ProductListItemProps } from '../ProductListItem/ProductListItem'
5
6
  import { ProductListItemRenderer } from './renderer'
6
7
 
8
+ type ComponentState = {
9
+ size?: 'normal' | 'small'
10
+ }
11
+
7
12
  export type ProductItemsGridProps = {
8
13
  items?:
9
14
  | Array<(ProductListItemFragment & ProductListItemProps) | null | undefined>
@@ -12,9 +17,14 @@ export type ProductItemsGridProps = {
12
17
  renderers: ProductListItemRenderer
13
18
  loadingEager?: number
14
19
  title: string
15
- size?: 'normal' | 'small'
16
20
  sx?: BoxProps['sx']
17
- } & Pick<ProductListItemProps, 'onClick' | 'titleComponent'>
21
+ } & Pick<ProductListItemProps, 'onClick' | 'titleComponent'> &
22
+ ComponentState
23
+
24
+ const slots = ['root'] as const
25
+ const name = 'ProductListItemsBase' as const
26
+
27
+ const { withState } = extendableComponent<ComponentState, typeof name, typeof slots>(name, slots)
18
28
 
19
29
  export function ProductListItemsBase(props: ProductItemsGridProps) {
20
30
  const {
@@ -27,41 +37,51 @@ export function ProductListItemsBase(props: ProductItemsGridProps) {
27
37
  onClick,
28
38
  } = props
29
39
 
40
+ const classes = withState({ size })
41
+
30
42
  return (
31
- <Box
32
- sx={[
33
- (theme) => ({
34
- display: 'grid',
35
- gridColumnGap: theme.spacings.md,
36
- gridRowGap: theme.spacings.md,
37
- }),
38
- size === 'small' && {
39
- gridTemplateColumns: `repeat(auto-fill, minmax(${responsiveVal(150, 280)}, 1fr))`,
40
- },
41
- size === 'normal' && {
42
- gridTemplateColumns: { xs: `repeat(2, 1fr)`, md: `repeat(3, 1fr)`, lg: `repeat(4, 1fr)` },
43
- },
44
- ...(Array.isArray(sx) ? sx : [sx]),
45
- ]}
46
- >
47
- {items?.map((item, idx) =>
48
- item ? (
49
- <RenderType
50
- key={item.uid ?? ''}
51
- renderer={renderers}
52
- sizes={
53
- size === 'small'
54
- ? { 0: '100vw', 354: '50vw', 675: '30vw', 1255: '23vw', 1500: '337px' }
55
- : { 0: '100vw', 367: '48vw', 994: '30vw', 1590: '23vw', 1920: '443px' }
56
- }
57
- {...item}
58
- loading={loadingEager > idx ? 'eager' : 'lazy'}
59
- titleComponent={titleComponent}
60
- onClick={onClick}
61
- noReport
62
- />
63
- ) : null,
64
- )}
65
- </Box>
43
+ <AddProductsToCartForm>
44
+ <Box
45
+ className={classes.root}
46
+ sx={[
47
+ (theme) => ({
48
+ display: 'grid',
49
+ gridColumnGap: theme.spacings.md,
50
+ gridRowGap: theme.spacings.md,
51
+
52
+ '&.sizeSmall': {
53
+ gridTemplateColumns: `repeat(auto-fill, minmax(${responsiveVal(150, 280)}, 1fr))`,
54
+ },
55
+ '&.sizeNormal': {
56
+ gridTemplateColumns: {
57
+ xs: `repeat(2, 1fr)`,
58
+ md: `repeat(3, 1fr)`,
59
+ lg: `repeat(4, 1fr)`,
60
+ },
61
+ },
62
+ }),
63
+ ...(Array.isArray(sx) ? sx : [sx]),
64
+ ]}
65
+ >
66
+ {items?.map((item, idx) =>
67
+ item ? (
68
+ <RenderType
69
+ key={item.uid ?? ''}
70
+ renderer={renderers}
71
+ sizes={
72
+ size === 'small'
73
+ ? { 0: '100vw', 354: '50vw', 675: '30vw', 1255: '23vw', 1500: '337px' }
74
+ : { 0: '100vw', 367: '48vw', 994: '30vw', 1590: '23vw', 1920: '443px' }
75
+ }
76
+ {...item}
77
+ loading={loadingEager > idx ? 'eager' : 'lazy'}
78
+ titleComponent={titleComponent}
79
+ onClick={onClick}
80
+ noReport
81
+ />
82
+ ) : null,
83
+ )}
84
+ </Box>
85
+ </AddProductsToCartForm>
66
86
  )
67
87
  }
@@ -1,5 +1,4 @@
1
1
  import type {
2
- Exact,
3
2
  Maybe,
4
3
  Scalars,
5
4
  ProductAttributeFilterInput,
@@ -12,16 +11,16 @@ import type {
12
11
 
13
12
  /** This is mainly based on ProductListQueryVariables */
14
13
  export type ProductListParams = {
15
- pageSize?: Maybe<Scalars['Int']>
16
- currentPage?: Maybe<Scalars['Int']>
14
+ pageSize?: Maybe<Scalars['Int']['input']>
15
+ currentPage?: Maybe<Scalars['Int']['input']>
17
16
  filters: ProductAttributeFilterInput
18
17
  sort: ProductAttributeSortInput
19
- search?: Maybe<Scalars['String']>
18
+ search?: Maybe<Scalars['String']['input']>
20
19
  url: string
21
20
  }
22
21
 
23
22
  export type ProductFilterParams = {
24
- pageSize?: Maybe<Scalars['Int']>
23
+ pageSize?: Maybe<Scalars['Int']['input']>
25
24
  currentPage: number
26
25
  filters: ProductAttributeFilterInput
27
26
  sort: keyof ProductAttributeSortInput | null
@@ -12,6 +12,7 @@ export type ProductListLinkProps = LinkProps &
12
12
  children?: React.ReactNode
13
13
  }
14
14
 
15
+ /** @deprecated Use productLinkList() instead */
15
16
  export const ProductListLink = React.forwardRef<HTMLAnchorElement, ProductListLinkProps>(
16
17
  (props, ref) => {
17
18
  const { setParams } = useProductListParamsContext()
@@ -1,7 +1,7 @@
1
1
  import { Pagination } from '@graphcommerce/next-ui'
2
- import { PaginationProps } from '@mui/material'
2
+ import { Link, PaginationProps } from '@mui/material'
3
+ import { productListLink } from '../../hooks/useProductListLink'
3
4
  import { ProductListParams } from '../ProductListItems/filterTypes'
4
- import { ProductListLink } from '../ProductListLink/ProductListLink'
5
5
  import { ProductListPaginationFragment } from './ProductListPagination.gql'
6
6
 
7
7
  export type ProductPaginationProps = ProductListPaginationFragment &
@@ -20,11 +20,18 @@ export function ProductListPagination({
20
20
  <Pagination
21
21
  count={page_info?.total_pages}
22
22
  page={page_info?.current_page ?? 1}
23
- renderLink={(_, icon, btnProps) => (
24
- <ProductListLink {...btnProps} {...params} currentPage={btnProps.page} color='inherit'>
25
- {icon}
26
- </ProductListLink>
27
- )}
23
+ renderLink={(_, icon, btnProps) => {
24
+ const suffix = btnProps.page === 1 ? '' : `#products`
25
+ return (
26
+ <Link
27
+ {...btnProps}
28
+ href={`${productListLink({ ...params, currentPage: btnProps.page })}${suffix}`}
29
+ color='inherit'
30
+ >
31
+ {icon}
32
+ </Link>
33
+ )
34
+ }}
28
35
  {...paginationProps}
29
36
  />
30
37
  )
@@ -8,7 +8,7 @@ const { classes, selectors } = extendableComponent('ProductListPrice', [
8
8
  'discountPrice',
9
9
  ] as const)
10
10
 
11
- type ProductListPriceProps = ProductListPriceFragment & Pick<TypographyProps, 'sx'>
11
+ export type ProductListPriceProps = ProductListPriceFragment & Pick<TypographyProps, 'sx'>
12
12
 
13
13
  export function ProductListPrice(props: ProductListPriceProps) {
14
14
  const { regular_price, final_price, sx } = props
@@ -0,0 +1,2 @@
1
+ export * from './ProductListPrice.gql'
2
+ export * from './ProductListPrice'
@@ -5,16 +5,17 @@ export type ProductPageAddToCartRowProps = {
5
5
  sx?: SxProps<Theme>
6
6
  children: React.ReactNode
7
7
  after?: React.ReactNode
8
+ // eslint-disable-next-line react/no-unused-prop-types
8
9
  product: UseAddProductsToCartActionFragment
9
10
  }
10
11
 
11
12
  export function ProductPageAddToCartRow(props: ProductPageAddToCartRowProps) {
12
- const { sx, children, after, product } = props
13
+ const { sx, children, after } = props
13
14
  return (
14
15
  <>
15
16
  <Box
16
17
  sx={[
17
- (theme) => ({ display: 'flex', alignItems: 'start', columnGap: theme.spacings.xs }),
18
+ (theme) => ({ display: 'flex', alignItems: 'center', columnGap: theme.spacings.xs }),
18
19
  ...(Array.isArray(sx) ? sx : [sx]),
19
20
  ]}
20
21
  >
@@ -1,7 +1,7 @@
1
1
  import { usePrevPageRouter } from '@graphcommerce/framer-next-pages'
2
2
  import { filterNonNullableKeys } from '@graphcommerce/next-ui'
3
3
  import { Trans } from '@lingui/react'
4
- import { Breadcrumbs, BreadcrumbsProps, Container, Link, Typography } from '@mui/material'
4
+ import { Breadcrumbs, BreadcrumbsProps, Link, Typography } from '@mui/material'
5
5
  import { productPageCategory } from '../ProductPageCategory/productPageCategory'
6
6
  import { ProductPageBreadcrumbFragment } from './ProductPageBreadcrumb.gql'
7
7
 
@@ -22,7 +22,7 @@ export function ProductPageBreadcrumb(props: ProductPageBreadcrumbsProps) {
22
22
  </Link>
23
23
  {filterNonNullableKeys(category?.breadcrumbs, ['category_level'])
24
24
  .sort((a, b) => a.category_level - b.category_level)
25
- .map((breadcrumb, i) => (
25
+ .map((breadcrumb) => (
26
26
  <Link
27
27
  underline='hover'
28
28
  key={breadcrumb.category_uid}
@@ -4,4 +4,5 @@ fragment ProductPageDescription on ProductInterface {
4
4
  description {
5
5
  ...ComplexTextValue
6
6
  }
7
+ url_key
7
8
  }
@@ -6,12 +6,14 @@ import {
6
6
  } from '@graphcommerce/next-ui'
7
7
  import { Box, SxProps, Theme, Typography } from '@mui/material'
8
8
  import { Variant } from '@mui/material/styles/createTypography'
9
+ import { ProductPageName } from '../ProductPageName'
9
10
  import { ProductPageDescriptionFragment } from './ProductPageDescription.gql'
10
11
 
11
12
  export type ProductPageDescriptionProps = ProductPageDescriptionFragment &
12
13
  Omit<ColumnTwoWithTopProps, 'top' | 'left'> & {
13
14
  sx?: SxProps<Theme>
14
15
  fontSize?: 'responsive' | Variant
16
+ product: ProductPageDescriptionFragment
15
17
  }
16
18
 
17
19
  const componentName = 'ProductPageDescription'
@@ -20,7 +22,7 @@ const parts = ['root', 'description'] as const
20
22
  const { classes } = extendableComponent(componentName, parts)
21
23
 
22
24
  export function ProductPageDescription(props: ProductPageDescriptionProps) {
23
- const { description, name, right, fontSize = 'subtitle1', sx = [] } = props
25
+ const { product, right, fontSize = 'subtitle1', sx = [] } = props
24
26
 
25
27
  return (
26
28
  <ColumnTwoWithTop
@@ -28,15 +30,15 @@ export function ProductPageDescription(props: ProductPageDescriptionProps) {
28
30
  sx={sx}
29
31
  top={
30
32
  <Typography variant='h1' component='h1'>
31
- {name}
33
+ <ProductPageName product={product} />
32
34
  </Typography>
33
35
  }
34
36
  left={
35
- description && (
37
+ product.description && (
36
38
  <Box
37
39
  className={classes.description}
38
40
  // eslint-disable-next-line react/no-danger
39
- dangerouslySetInnerHTML={{ __html: description.html }}
41
+ dangerouslySetInnerHTML={{ __html: product.description.html }}
40
42
  sx={[
41
43
  {
42
44
  '& p:first-of-type': {
@@ -7,4 +7,5 @@ fragment ProductPageGallery on ProductInterface {
7
7
  ...ProductImage
8
8
  ...ProductVideo
9
9
  }
10
+ url_key
10
11
  }
@@ -10,16 +10,14 @@ export type ProductPageGalleryRenderers = TypeRenderer<
10
10
  NonNullable<NonNullable<ProductPageGalleryFragment['media_gallery']>[0]>
11
11
  >
12
12
 
13
- export type ProductPageGalleryProps = ProductPageGalleryFragment &
14
- Omit<SidebarGalleryProps, 'sidebar' | 'images'> & { children?: React.ReactNode }
13
+ export type ProductPageGalleryProps = Omit<SidebarGalleryProps, 'sidebar' | 'images'> & {
14
+ product: ProductPageGalleryFragment
15
+ children?: React.ReactNode
16
+ }
15
17
 
16
18
  export function ProductPageGallery(props: ProductPageGalleryProps) {
17
- const {
18
- media_gallery,
19
- children,
20
- aspectRatio: [width, height] = [1532, 1678],
21
- ...sidebarProps
22
- } = props
19
+ const { product, children, aspectRatio: [width, height] = [1532, 1678], ...sidebarProps } = props
20
+ const { media_gallery } = product
23
21
 
24
22
  return (
25
23
  <SidebarGallery
@@ -3,16 +3,18 @@ fragment ProductPageMeta on ProductInterface {
3
3
  sku
4
4
  name
5
5
  url_key
6
+ url_rewrites {
7
+ url
8
+ }
6
9
  meta_title
7
10
  meta_description
8
11
  price_range {
9
12
  minimum_price {
10
13
  final_price {
11
- value
12
- currency
14
+ ...Money
13
15
  }
14
16
  regular_price {
15
- value
17
+ ...Money
16
18
  }
17
19
  }
18
20
  }
@@ -1,9 +1,15 @@
1
1
  import { PageMeta } from '@graphcommerce/magento-store'
2
- import { useCanonical } from '@graphcommerce/next-ui'
3
- import { useProductLink } from '../../hooks/useProductLink'
2
+ import { PageMetaProps } from '@graphcommerce/next-ui'
3
+ import { productLink } from '../../hooks/useProductLink'
4
4
  import { ProductPageMetaFragment } from './ProductPageMeta.gql'
5
5
 
6
- export function ProductPageMeta(props: ProductPageMetaFragment) {
6
+ export type ProductPageMetaProps = { product: ProductPageMetaFragment } & Pick<
7
+ PageMetaProps,
8
+ 'children' | 'ogImage' | 'ogImageUseFallback'
9
+ >
10
+
11
+ export function ProductPageMeta(props: ProductPageMetaProps) {
12
+ const { product, ...rest } = props
7
13
  const {
8
14
  sku,
9
15
  categories,
@@ -14,45 +20,37 @@ export function ProductPageMeta(props: ProductPageMetaFragment) {
14
20
  meta_description,
15
21
  url_key,
16
22
  __typename,
17
- } = props
18
- const productLink = useProductLink({ url_key, __typename })
19
- const canonical = useCanonical(productLink)
23
+ } = product
20
24
 
21
25
  return (
22
26
  <PageMeta
23
27
  title={meta_title ?? name ?? ''}
24
28
  metaDescription={meta_description ?? name ?? ''}
25
- canonical={productLink}
29
+ canonical={productLink({ url_key, __typename })}
30
+ ogImage={media_gallery?.[0]?.url}
31
+ ogType='product'
32
+ {...rest}
26
33
  >
27
- {sku && (
28
- <>
29
- <meta property='type' content='product' key='og-type' />
30
- <meta property='product:retailer_part_no' content={sku} key='og-sku' />
31
- </>
32
- )}
33
- {name && <meta property='og:title' content={name} key='og-title' />}
34
- {media_gallery?.[0]?.url && (
35
- <meta property='og:image' content={media_gallery[0].url} key='og-image' />
36
- )}
34
+ {sku && <meta property='product:retailer_part_no' content={sku} key='og-product-sku' />}
37
35
  {price_range?.minimum_price?.regular_price?.value && (
38
36
  <meta
39
37
  property='product:price:amount'
40
38
  content={price_range.minimum_price.regular_price.value.toString()}
41
- key='og-price'
39
+ key='og-product-price'
42
40
  />
43
41
  )}
44
42
  {price_range?.minimum_price?.final_price?.value && (
45
43
  <meta
46
44
  property='product:sale_price:amount'
47
45
  content={price_range.minimum_price.final_price.value.toString()}
48
- key='og-sale-price'
46
+ key='og-product-sale-price'
49
47
  />
50
48
  )}
51
49
  {price_range?.minimum_price?.final_price?.currency && (
52
50
  <meta
53
51
  property='product:price:currency'
54
52
  content={price_range.minimum_price.final_price.currency}
55
- key='og-currency'
53
+ key='og-product-currency'
56
54
  />
57
55
  )}
58
56
  {categories &&
@@ -61,7 +59,6 @@ export function ProductPageMeta(props: ProductPageMetaFragment) {
61
59
  <meta property='product:category' content={category.name} key={category.uid} />
62
60
  ) : null,
63
61
  )}
64
- {canonical && <meta property='og:url' content={canonical} key='og-url' />}
65
62
  </PageMeta>
66
63
  )
67
64
  }
@@ -0,0 +1,4 @@
1
+ fragment ProductPageName on ProductInterface {
2
+ name
3
+ url_key
4
+ }
@@ -0,0 +1,10 @@
1
+ import { ProductPageNameFragment } from './ProductPageName.gql'
2
+
3
+ export type ProductPageNameProps = {
4
+ product: ProductPageNameFragment
5
+ }
6
+
7
+ export const ProductPageName = (props: ProductPageNameProps) => {
8
+ const { product } = props
9
+ return <>{product.name}</>
10
+ }
@@ -0,0 +1 @@
1
+ export * from './ProductPageName'
@@ -1,4 +1,5 @@
1
1
  fragment ProductPagePrice on ProductInterface {
2
+ url_key
2
3
  price_range {
3
4
  minimum_price {
4
5
  regular_price {
@@ -1,10 +1,10 @@
1
1
  import { useWatch } from '@graphcommerce/ecommerce-ui'
2
2
  import { Money } from '@graphcommerce/magento-store'
3
- import { useFormAddProductsToCart } from '../AddProductsToCart'
3
+ import { AddToCartItemSelector, useFormAddProductsToCart } from '../AddProductsToCart'
4
4
  import { ProductPagePriceFragment } from './ProductPagePrice.gql'
5
5
  import { getProductTierPrice } from './getProductTierPrice'
6
6
 
7
- type ProductPagePriceProps = { product: ProductPagePriceFragment; index?: number }
7
+ export type ProductPagePriceProps = { product: ProductPagePriceFragment } & AddToCartItemSelector
8
8
 
9
9
  export function ProductPagePrice(props: ProductPagePriceProps) {
10
10
  const { product, index = 0 } = props
@@ -1,4 +1,5 @@
1
1
  fragment ProductShortDescription on ProductInterface {
2
+ url_key
2
3
  short_description {
3
4
  ...ComplexTextValue
4
5
  }
@@ -2,12 +2,16 @@ import { extendableComponent } from '@graphcommerce/next-ui'
2
2
  import { SxProps, Theme, Typography } from '@mui/material'
3
3
  import { ProductShortDescriptionFragment } from './ProductShortDescription.gql'
4
4
 
5
- type ProductShortDescriptionProps = ProductShortDescriptionFragment & { sx?: SxProps<Theme> }
5
+ export type ProductShortDescriptionProps = {
6
+ product: ProductShortDescriptionFragment
7
+ sx?: SxProps<Theme>
8
+ }
6
9
 
7
10
  const { classes } = extendableComponent('ProductShortDescription', ['description'] as const)
8
11
 
9
12
  export function ProductShortDescription(props: ProductShortDescriptionProps) {
10
- const { short_description, sx = [] } = props
13
+ const { product, sx = [] } = props
14
+ const { short_description } = product
11
15
 
12
16
  return (
13
17
  <Typography
@@ -2,14 +2,18 @@ import { responsiveVal, Row, SectionContainer, extendableComponent } from '@grap
2
2
  import { Box, SxProps, Theme } from '@mui/material'
3
3
  import { ProductSpecsFragment } from './ProductSpecs.gql'
4
4
 
5
- export type ProductSpecsProps = ProductSpecsFragment & { title?: string; sx?: SxProps<Theme> }
5
+ export type ProductSpecsProps = ProductSpecsFragment & {
6
+ title?: string
7
+ sx?: SxProps<Theme>
8
+ children?: React.ReactNode
9
+ }
6
10
 
7
11
  const name = 'ProductSpecs' as const
8
12
  const parts = ['root', 'specs', 'options'] as const
9
13
  const { classes } = extendableComponent(name, parts)
10
14
 
11
15
  export function ProductSpecs(props: ProductSpecsProps) {
12
- const { aggregations, title, sx = [] } = props
16
+ const { aggregations, title, children, sx = [] } = props
13
17
  const filter = ['price', 'category_id', 'size', 'new', 'sale', 'color']
14
18
  const specs = aggregations?.filter(
15
19
  (attr) => !filter.includes(attr?.attribute_code ?? '') && attr?.options?.[0]?.value !== '0',
@@ -53,6 +57,7 @@ export function ProductSpecs(props: ProductSpecsProps) {
53
57
  </li>
54
58
  ))}
55
59
  </Box>
60
+ {children}
56
61
  </SectionContainer>
57
62
  </Row>
58
63
  )
@@ -1,5 +1,5 @@
1
1
  export * from './AddProductsToCart'
2
- export * from './JsonLdProduct/jsonLdProduct'
2
+ export * from './JsonLdProduct'
3
3
  export * from './ProductAddToCart'
4
4
  export * from './ProductCustomizable'
5
5
  export * from './ProductFiltersPro'
@@ -11,7 +11,6 @@ export * from './ProductListItem/ProductListItem'
11
11
  export * from './ProductListItems/filteredProductList'
12
12
  export * from './ProductListItems/filterTypes'
13
13
  export * from './ProductListItems/getFilterTypes'
14
- export * from './ProductListItems/ProductListItems'
15
14
  export * from './ProductListItems/ProductListItems.gql'
16
15
  export * from './ProductListItems/ProductListItemsBase'
17
16
  export * from './ProductListItems/ProductListParamsProvider'
@@ -19,19 +18,23 @@ export * from './ProductListItems/renderer'
19
18
  export * from './ProductListLink/ProductListLink'
20
19
  export * from './ProductListPagination/ProductListPagination'
21
20
  export * from './ProductListSort'
21
+ export * from './ProductPageName'
22
22
  export * from './ProductPage/ProductPageAddToCartRow'
23
23
  export * from './ProductPageBreadcrumb'
24
24
  export * from './ProductPageCategory/productPageCategory'
25
25
  export * from './ProductPageDescription/ProductPageDescription'
26
26
  export * from './ProductPageGallery/ProductPageGallery'
27
27
  export * from './ProductPageMeta/ProductPageMeta'
28
+ export * from './ProductPageMeta/ProductPageMeta.gql'
28
29
  export * from './ProductPagePrice'
29
30
  export * from './ProductRelated/RelatedProducts.gql'
30
31
  export * from './ProductShortDescription/ProductShortDescription'
31
32
  export * from './ProductShortDescription/ProductShortDescription.gql'
32
33
  export * from './ProductSidebarDelivery/ProductSidebarDelivery'
33
34
  export * from './ProductSpecs/ProductSpecs'
35
+ export * from './ProductSpecs/ProductSpecs.gql'
34
36
  export * from './ProductStaticPaths/getProductStaticPaths'
35
37
  export * from './ProductStaticPaths/getSitemapPaths'
36
38
  export * from './ProductUpsells/UpsellProducts.gql'
37
39
  export * from './ProductWeight/ProductWeight'
40
+ export * from './ProductListPrice'
@@ -5,7 +5,7 @@ import {
5
5
  ProductListParams,
6
6
  } from '../components/ProductListItems/filterTypes'
7
7
 
8
- export function createProductListLink(props: ProductListParams): string {
8
+ export function productListLink(props: ProductListParams): string {
9
9
  const { url, sort, currentPage, pageSize, filters: incoming } = props
10
10
  const isSearch = url.startsWith('search')
11
11
  const filters = isSearch ? incoming : { ...incoming, category_uid: undefined }
@@ -43,5 +43,5 @@ export function createProductListLink(props: ProductListParams): string {
43
43
  }
44
44
 
45
45
  export function useProductListLink(props: ProductListParams): string {
46
- return createProductListLink({ ...props, url: `${props.url}` })
46
+ return productListLink({ ...props, url: `${props.url}` })
47
47
  }