@graphcommerce/magento-category 8.1.0-canary.9 → 9.0.0-canary.55

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 CHANGED
@@ -1,5 +1,110 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.55
4
+
5
+ ## 9.0.0-canary.54
6
+
7
+ ## 8.1.0-canary.53
8
+
9
+ ## 8.1.0-canary.52
10
+
11
+ ## 8.1.0-canary.51
12
+
13
+ ## 8.1.0-canary.50
14
+
15
+ ## 8.1.0-canary.49
16
+
17
+ ## 8.1.0-canary.48
18
+
19
+ ## 8.1.0-canary.47
20
+
21
+ ## 8.1.0-canary.46
22
+
23
+ ## 8.1.0-canary.45
24
+
25
+ ## 8.1.0-canary.44
26
+
27
+ ## 8.1.0-canary.43
28
+
29
+ ## 8.1.0-canary.42
30
+
31
+ ## 8.1.0-canary.41
32
+
33
+ ## 8.1.0-canary.40
34
+
35
+ ## 8.1.0-canary.39
36
+
37
+ ## 8.1.0-canary.38
38
+
39
+ ## 8.1.0-canary.37
40
+
41
+ ## 8.1.0-canary.36
42
+
43
+ ## 8.1.0-canary.35
44
+
45
+ ## 8.1.0-canary.34
46
+
47
+ ## 8.1.0-canary.33
48
+
49
+ ## 8.1.0-canary.32
50
+
51
+ ## 8.1.0-canary.31
52
+
53
+ ## 8.1.0-canary.30
54
+
55
+ ## 8.1.0-canary.29
56
+
57
+ ## 8.1.0-canary.28
58
+
59
+ ## 8.1.0-canary.27
60
+
61
+ ### Minor Changes
62
+
63
+ - [#2273](https://github.com/graphcommerce-org/graphcommerce/pull/2273) [`77955c5`](https://github.com/graphcommerce-org/graphcommerce/commit/77955c56ac8633ab1c5e0f3ddb25e3a87236e2bb) - Improve Breadcrumbs on Category and Product pages
64
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
65
+
66
+ - [#2273](https://github.com/graphcommerce-org/graphcommerce/pull/2273) [`aa56540`](https://github.com/graphcommerce-org/graphcommerce/commit/aa56540af91638c09e4c7a0a1648aaa6c5fa0afb) - If a category has no children, the sibling links will be shown on the category page.
67
+ ([@Jessevdpoel](https://github.com/Jessevdpoel))
68
+
69
+ ## 8.1.0-canary.26
70
+
71
+ ## 8.1.0-canary.25
72
+
73
+ ## 8.1.0-canary.24
74
+
75
+ ## 8.1.0-canary.23
76
+
77
+ ## 8.1.0-canary.22
78
+
79
+ ## 8.1.0-canary.21
80
+
81
+ ## 8.1.0-canary.20
82
+
83
+ ## 8.1.0-canary.19
84
+
85
+ ## 8.1.0-canary.18
86
+
87
+ ## 8.1.0-canary.17
88
+
89
+ ## 8.1.0-canary.16
90
+
91
+ ## 8.1.0-canary.15
92
+
93
+ ### Patch Changes
94
+
95
+ - [#2267](https://github.com/graphcommerce-org/graphcommerce/pull/2267) [`9d5fd11`](https://github.com/graphcommerce-org/graphcommerce/commit/9d5fd11c7130612e80523608ab442976f3f5ddc5) - make the CategoryHeroNav fragment injectable and add image to the childeren
96
+ ([@carlocarels90](https://github.com/carlocarels90))
97
+
98
+ ## 8.1.0-canary.14
99
+
100
+ ## 8.1.0-canary.13
101
+
102
+ ## 8.1.0-canary.12
103
+
104
+ ## 8.1.0-canary.11
105
+
106
+ ## 8.1.0-canary.10
107
+
3
108
  ## 8.1.0-canary.9
4
109
 
5
110
  ## 8.1.0-canary.8
@@ -5,6 +5,9 @@ import { CategoryBreadcrumbFragment } from './CategoryBreadcrumb.gql'
5
5
 
6
6
  type CategoryPageBreadcrumbsProps = CategoryBreadcrumbFragment & Omit<BreadcrumbsProps, 'children'>
7
7
 
8
+ /**
9
+ * @deprecated Please use CategoryBreadcrumbs
10
+ */
8
11
  export function CategoryBreadcrumb(props: CategoryPageBreadcrumbsProps) {
9
12
  const { breadcrumbs, name, ...breadcrumbsProps } = props
10
13
 
@@ -0,0 +1,40 @@
1
+ import {
2
+ Breadcrumbs,
3
+ BreadcrumbsJsonLd,
4
+ BreadcrumbsProps,
5
+ jsonLdBreadcrumb,
6
+ } from '@graphcommerce/next-ui'
7
+ import { useRouter } from 'next/router'
8
+ import type { BreadcrumbList } from 'schema-dts'
9
+ import { CategoryBreadcrumbFragment } from './CategoryBreadcrumb.gql'
10
+ import { categoryToBreadcrumbs } from './categoryToBreadcrumbs'
11
+
12
+ export type CategoryBreadcrumbsProps = Omit<BreadcrumbsProps, 'breadcrumbs'> & {
13
+ category?: CategoryBreadcrumbFragment
14
+ }
15
+
16
+ export function CategoryBreadcrumbs(props: CategoryBreadcrumbsProps) {
17
+ const { category, sx, ...breadcrumbsProps } = props
18
+ const router = useRouter()
19
+
20
+ if (!category) return null
21
+
22
+ const breadcrumbs = categoryToBreadcrumbs(category)
23
+
24
+ return (
25
+ <>
26
+ <BreadcrumbsJsonLd<BreadcrumbList>
27
+ breadcrumbs={breadcrumbs}
28
+ render={(bc) => ({
29
+ '@context': 'https://schema.org',
30
+ ...jsonLdBreadcrumb(bc, router),
31
+ })}
32
+ />
33
+ <Breadcrumbs
34
+ breadcrumbs={breadcrumbs}
35
+ {...breadcrumbsProps}
36
+ sx={[...(Array.isArray(sx) ? sx : [sx])]}
37
+ />
38
+ </>
39
+ )
40
+ }
@@ -0,0 +1,30 @@
1
+ import { productListLink } from '@graphcommerce/magento-product'
2
+ import { BreadcrumbsType, filterNonNullableKeys } from '@graphcommerce/next-ui'
3
+ import { CategoryBreadcrumbFragment } from './CategoryBreadcrumb.gql'
4
+
5
+ export function categoryToBreadcrumbs(
6
+ category: CategoryBreadcrumbFragment,
7
+ ): BreadcrumbsType['breadcrumbs'] {
8
+ if (!category.url_path || !category.name) return []
9
+
10
+ return [
11
+ ...filterNonNullableKeys(category.breadcrumbs, [
12
+ 'category_level',
13
+ 'category_name',
14
+ 'category_url_path',
15
+ ])
16
+ .sort((a, b) => a.category_level - b.category_level)
17
+ .map(({ category_url_path, category_name }) => ({
18
+ href: productListLink({ url: category_url_path, filters: {}, sort: {} }),
19
+ name: category_name,
20
+ })),
21
+ {
22
+ href: productListLink({
23
+ url: category.url_path,
24
+ filters: {},
25
+ sort: {},
26
+ }),
27
+ name: category.name,
28
+ },
29
+ ]
30
+ }
@@ -1,2 +1,4 @@
1
- export * from './CategoryBreadcrumb'
2
1
  export * from './CategoryBreadcrumb.gql'
2
+ export * from './CategoryBreadcrumb'
3
+ export * from './CategoryBreadcrumbs'
4
+ export * from './categoryToBreadcrumbs'
@@ -1,10 +1,6 @@
1
1
  fragment CategoryChildren on CategoryTree {
2
2
  uid
3
3
  children {
4
- uid
5
- name
6
- level
7
- url_path
8
- include_in_menu
4
+ ...NavigationItem
9
5
  }
10
6
  }
@@ -1,7 +1,6 @@
1
1
  import { Scroller, ScrollerProvider } from '@graphcommerce/framer-scroller'
2
- import { ProductListParams } from '@graphcommerce/magento-product'
3
- import { productListLink } from '@graphcommerce/magento-product/hooks/useProductListLink'
4
- import { extendableComponent } from '@graphcommerce/next-ui'
2
+ import { ProductListParams, productListLink } from '@graphcommerce/magento-product'
3
+ import { extendableComponent, filterNonNullableKeys } from '@graphcommerce/next-ui'
5
4
  import { Box, Link, SxProps, Theme } from '@mui/material'
6
5
  import { CategoryChildrenFragment } from './CategoryChildren.gql'
7
6
 
@@ -17,75 +16,74 @@ const { classes } = extendableComponent(name, parts)
17
16
  export function CategoryChildren(props: CategoryChildrenProps) {
18
17
  const { children, params, sx = [] } = props
19
18
 
20
- const { currentPage, ...paramsWithoutCurrentPage } = params
19
+ const childItems = filterNonNullableKeys(children, ['url_path', 'name', 'include_in_menu']).map(
20
+ (category) => ({
21
+ name: category.name,
22
+ href: productListLink({
23
+ ...params,
24
+ currentPage: 0,
25
+ url: category.url_path,
26
+ filters: { category_uid: { eq: category.uid } },
27
+ }),
28
+ active: params.url === category.url_path,
29
+ }),
30
+ )
21
31
 
22
- if (!children || children.length === 0) return null
32
+ const hasNavigatableChildren = childItems.some((cat) => !cat.active)
33
+ if (!hasNavigatableChildren) return null
23
34
 
24
35
  return (
25
36
  <ScrollerProvider scrollSnapAlign='none'>
26
37
  <Box
27
38
  className={classes.container}
28
- sx={[
29
- (theme) => ({
30
- display: 'flex',
31
- justifyContent: 'center',
32
- marginBottom: theme.spacings.sm,
33
- }),
34
- ...(Array.isArray(sx) ? sx : [sx]),
35
- ]}
39
+ sx={[{ display: 'flex' }, ...(Array.isArray(sx) ? sx : [sx])]}
36
40
  >
37
41
  <Scroller
38
42
  className={classes.scroller}
39
43
  hideScrollbar
40
- sx={{ gridAutoColumns: `max-content` }}
44
+ sx={(theme) => ({
45
+ gridAutoColumns: `max-content`,
46
+ columnGap: theme.spacings.sm,
47
+ marginBottom: '-8px',
48
+ })}
41
49
  >
42
- {children.map((cat) => {
43
- if (!cat?.url_path || !cat.name || !cat.include_in_menu) return null
44
-
45
- return (
46
- <Link
47
- key={cat.url_path}
48
- underline='none'
49
- color='inherit'
50
- href={productListLink({
51
- ...paramsWithoutCurrentPage,
52
- url: cat.url_path,
53
- filters: { category_uid: { eq: cat.uid } },
54
- })}
55
- className={classes.link}
56
- sx={(theme) => ({
57
- whiteSpace: 'nowrap',
58
- display: 'block',
59
- marginRight: `${theme.spacings.xxs}`,
60
- marginLeft: `${theme.spacings.xxs}`,
61
- typography: 'h6',
62
- position: 'relative',
63
- paddingBottom: '8px',
50
+ {childItems.map((category) => (
51
+ <Link
52
+ key={category.href}
53
+ underline='none'
54
+ color='inherit'
55
+ href={category.href}
56
+ className={classes.link}
57
+ sx={(theme) => ({
58
+ whiteSpace: 'nowrap',
59
+ display: 'block',
60
+ typography: 'h6',
61
+ position: 'relative',
62
+ paddingBottom: '8px',
63
+ '&:before': {
64
+ content: '""',
65
+ width: 40,
66
+ height: 2,
67
+ background: theme.palette.primary.main,
68
+ position: 'absolute',
69
+ left: 0,
70
+ right: 0,
71
+ margin: '0 auto',
72
+ opacity: category.active ? 1 : 0,
73
+ transition: 'opacity .2s ease, bottom .2s ease',
74
+ bottom: category.active ? 5 : 0,
75
+ },
76
+ '&:hover': {
64
77
  '&:before': {
65
- content: '""',
66
- width: 40,
67
- height: 2,
68
- background: theme.palette.primary.main,
69
- position: 'absolute',
70
- left: 0,
71
- right: 0,
72
- margin: '0 auto',
73
- opacity: 0,
74
- transition: 'opacity .2s ease, bottom .2s ease',
75
- bottom: 0,
78
+ opacity: 1,
79
+ bottom: 5,
76
80
  },
77
- '&:hover': {
78
- '&:before': {
79
- opacity: 1,
80
- bottom: 5,
81
- },
82
- },
83
- })}
84
- >
85
- {cat.name}
86
- </Link>
87
- )
88
- })}
81
+ },
82
+ })}
83
+ >
84
+ {category.name}
85
+ </Link>
86
+ ))}
89
87
  </Scroller>
90
88
  </Box>
91
89
  </ScrollerProvider>
@@ -0,0 +1,7 @@
1
+ query CategorySiblings($parentUid: String!) {
2
+ categories(filters: { parent_category_uid: { eq: $parentUid } }) {
3
+ items {
4
+ ...NavigationItem
5
+ }
6
+ }
7
+ }
@@ -1,4 +1,4 @@
1
- fragment CategoryDescription on CategoryTree @injectable {
1
+ fragment CategoryDescription on CategoryTree {
2
2
  uid
3
3
  description
4
4
  name
@@ -2,16 +2,32 @@ import { extendableComponent } from '@graphcommerce/next-ui'
2
2
  import { Box, SxProps, Theme } from '@mui/material'
3
3
  import { CategoryDescriptionFragment } from './CategoryDescription.gql'
4
4
 
5
- export type CategoryDescriptionProps = Omit<CategoryDescriptionFragment, 'uid'> & {
6
- sx?: SxProps<Theme>
5
+ type StateProps = {
6
+ textAlignSm?: 'start' | 'center'
7
+ textAlignMd?: 'start' | 'center'
7
8
  }
8
-
9
- const cmpName = 'CategoryDescription' as const
9
+ const componentName = 'CategoryDescription' as const
10
10
  const parts = ['root'] as const
11
- const { classes } = extendableComponent(cmpName, parts)
11
+ const { withState } = extendableComponent<StateProps, typeof componentName, typeof parts>(
12
+ componentName,
13
+ parts,
14
+ )
15
+
16
+ export type CategoryDescriptionProps = Omit<CategoryDescriptionFragment, 'uid'> &
17
+ StateProps & { sx?: SxProps<Theme> }
12
18
 
13
19
  export function CategoryDescription(props: CategoryDescriptionProps) {
14
- const { name, description, display_mode, sx = [], ...divProps } = props
20
+ const {
21
+ name,
22
+ description,
23
+ display_mode,
24
+ sx = [],
25
+ textAlignSm = 'center',
26
+ textAlignMd = 'center',
27
+ ...divProps
28
+ } = props
29
+
30
+ const classes = withState({ textAlignSm, textAlignMd })
15
31
 
16
32
  return description ? (
17
33
  // eslint-disable-next-line react/no-danger
@@ -21,12 +37,20 @@ export function CategoryDescription(props: CategoryDescriptionProps) {
21
37
  dangerouslySetInnerHTML={{ __html: description }}
22
38
  sx={[
23
39
  (theme) => ({
24
- gridArea: 'description',
25
- margin: `0 auto ${theme.spacings.sm}`,
26
- padding: `0 ${theme.page.horizontal}`,
27
- textAlign: 'center',
28
- maxWidth: { md: '900px' },
29
40
  typography: 'subtitle1',
41
+ [theme.breakpoints.down('sm')]: {
42
+ textAlign: textAlignSm,
43
+ '&.textAlignSmCenter': {
44
+ mx: 'auto',
45
+ },
46
+ },
47
+ [theme.breakpoints.up('md')]: {
48
+ maxWidth: '900px',
49
+ textAlign: textAlignMd,
50
+ '&.textAlignMdCenter': {
51
+ mx: 'auto',
52
+ },
53
+ },
30
54
  }),
31
55
  ...(Array.isArray(sx) ? sx : [sx]),
32
56
  ]}
@@ -8,5 +8,6 @@ fragment CategoryHeroNav on CategoryTree {
8
8
  url_path
9
9
  name
10
10
  include_in_menu
11
+ image
11
12
  }
12
13
  }
@@ -14,8 +14,8 @@ const cmpName = 'CategoryHeroNav' as const
14
14
  const parts = ['wrapper', 'categories', 'title', 'placeholder'] as const
15
15
  const { classes } = extendableComponent(cmpName, parts)
16
16
 
17
- export function CategoryHeroNav({ children, title, asset, sx = [] }: CategoryHeroNavProps) {
18
- return (
17
+ export const CategoryHeroNav = React.memo<CategoryHeroNavProps>(
18
+ ({ children, title, asset, sx = [] }) => (
19
19
  <Row
20
20
  className={classes.wrapper}
21
21
  maxWidth={false}
@@ -133,5 +133,5 @@ export function CategoryHeroNav({ children, title, asset, sx = [] }: CategoryHer
133
133
  <Box>{asset}</Box>
134
134
  </Box>
135
135
  </Row>
136
- )
137
- }
136
+ ),
137
+ )
@@ -1,13 +1,13 @@
1
1
  import { LayoutTitle } from '@graphcommerce/next-ui'
2
2
  import { SxProps, Theme } from '@mui/material'
3
- import React from 'react'
3
+ import { memo } from 'react'
4
4
 
5
5
  type CategoryHeroNavTitleProps = {
6
6
  children: React.ReactNode
7
7
  sx?: SxProps<Theme>
8
8
  }
9
9
 
10
- export function CategoryHeroNavTitle(props: CategoryHeroNavTitleProps) {
10
+ export const CategoryHeroNavTitle = memo<CategoryHeroNavTitleProps>((props) => {
11
11
  const { children, sx = [] } = props
12
12
 
13
13
  return (
@@ -15,11 +15,9 @@ export function CategoryHeroNavTitle(props: CategoryHeroNavTitleProps) {
15
15
  variant='h1'
16
16
  sx={[
17
17
  (theme) => ({
18
- justifyContent: 'center',
19
18
  [theme.breakpoints.up('md')]: {
20
- margin: 0,
21
- alignItems: 'start',
22
- justifyContent: 'end',
19
+ m: 0,
20
+ justifyContent: 'start',
23
21
  },
24
22
  }),
25
23
  ...(Array.isArray(sx) ? sx : [sx]),
@@ -28,4 +26,4 @@ export function CategoryHeroNavTitle(props: CategoryHeroNavTitleProps) {
28
26
  {children}
29
27
  </LayoutTitle>
30
28
  )
31
- }
29
+ })
package/index.ts CHANGED
@@ -1,8 +1,16 @@
1
1
  export * from './components/CategoryChildren/CategoryChildren'
2
+ export * from './components/CategoryChildren/CategoryChildren.gql'
3
+ export * from './components/CategoryChildren/CategorySiblings.gql'
2
4
  export * from './components/CategoryDescription/CategoryDescription'
3
5
  export * from './components/CategoryHeroNav/CategoryHeroNav'
4
6
  export * from './components/CategoryHeroNav/CategoryHeroNavTitle'
5
7
  export * from './components/CategoryMeta/CategoryMeta'
8
+ export * from './utils/appendSiblingsAsChildren'
6
9
  export * from './utils/magentoMenuToNavigation'
10
+ export * from './utils/findParentBreadcrumbItem'
7
11
  export * from './queries/getCategoryStaticPaths'
8
12
  export * from './components/CategoryBreadcrumb'
13
+ export * from './queries/CategoryQueryFragment.gql'
14
+ export * from './queries/MenuQueryFragment.gql'
15
+ export * from './queries/NavigationItem.gql'
16
+ export * from './utils/useCategoryTree'
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/magento-category",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "8.1.0-canary.9",
5
+ "version": "9.0.0-canary.55",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,15 +12,15 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/eslint-config-pwa": "^8.1.0-canary.9",
16
- "@graphcommerce/framer-scroller": "^8.1.0-canary.9",
17
- "@graphcommerce/graphql": "^8.1.0-canary.9",
18
- "@graphcommerce/image": "^8.1.0-canary.9",
19
- "@graphcommerce/magento-product": "^8.1.0-canary.9",
20
- "@graphcommerce/magento-store": "^8.1.0-canary.9",
21
- "@graphcommerce/next-ui": "^8.1.0-canary.9",
22
- "@graphcommerce/prettier-config-pwa": "^8.1.0-canary.9",
23
- "@graphcommerce/typescript-config-pwa": "^8.1.0-canary.9",
15
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.55",
16
+ "@graphcommerce/framer-scroller": "^9.0.0-canary.55",
17
+ "@graphcommerce/graphql": "^9.0.0-canary.55",
18
+ "@graphcommerce/image": "^9.0.0-canary.55",
19
+ "@graphcommerce/magento-product": "^9.0.0-canary.55",
20
+ "@graphcommerce/magento-store": "^9.0.0-canary.55",
21
+ "@graphcommerce/next-ui": "^9.0.0-canary.55",
22
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.55",
23
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.55",
24
24
  "@lingui/core": "^4.2.1",
25
25
  "@lingui/macro": "^4.2.1",
26
26
  "@lingui/react": "^4.2.1",
@@ -1,4 +1,4 @@
1
- fragment CategoryPathFragment on CategoryTree @injectable {
1
+ fragment CategoryPathFragment on CategoryTree {
2
2
  uid
3
3
  url_path
4
4
  children {
@@ -1,7 +1,8 @@
1
- fragment NavigationItem on CategoryTree @injectable {
1
+ fragment NavigationItem on CategoryTree {
2
2
  uid
3
3
  include_in_menu
4
4
  name
5
5
  url_path
6
6
  level
7
+ is_anchor
7
8
  }
@@ -0,0 +1,23 @@
1
+ import { ApolloClient } from '@graphcommerce/graphql'
2
+ import { CategoryBreadcrumbFragment } from '../components/CategoryBreadcrumb'
3
+ import { CategoryChildrenFragment } from '../components/CategoryChildren/CategoryChildren.gql'
4
+ import { CategorySiblingsDocument } from '../components/CategoryChildren/CategorySiblings.gql'
5
+ import { findParentBreadcrumbItem } from './findParentBreadcrumbItem'
6
+
7
+ export function appendSiblingsAsChildren(
8
+ categoryPromise: Promise<
9
+ (CategoryBreadcrumbFragment & CategoryChildrenFragment) | null | undefined
10
+ >,
11
+ client: ApolloClient<object>,
12
+ ) {
13
+ return categoryPromise.then(async (cat) => {
14
+ const parentUid = findParentBreadcrumbItem(cat)?.category_uid
15
+ if (!cat || (cat?.children?.length ?? 0) > 0 || !parentUid) return
16
+
17
+ const res = await client.query({
18
+ query: CategorySiblingsDocument,
19
+ variables: { parentUid },
20
+ })
21
+ cat.children = res.data.categories?.items
22
+ })
23
+ }
@@ -0,0 +1,12 @@
1
+ import { filterNonNullableKeys } from '@graphcommerce/next-ui'
2
+ import { CategoryBreadcrumbFragment } from '../components/CategoryBreadcrumb'
3
+
4
+ export function findParentBreadcrumbItem(
5
+ category: CategoryBreadcrumbFragment | null | undefined,
6
+ ): NonNullable<CategoryBreadcrumbFragment['breadcrumbs']>[number] | undefined {
7
+ const parentCategoryPath = category?.url_path?.split('/').slice(0, -1).join('/')
8
+
9
+ return filterNonNullableKeys(category?.breadcrumbs, ['category_url_path']).find(
10
+ (c) => parentCategoryPath === c.category_url_path,
11
+ )
12
+ }
@@ -0,0 +1,71 @@
1
+ import { ProductListParams } from '@graphcommerce/magento-product'
2
+ import { filterNonNullableKeys } from '@graphcommerce/next-ui'
3
+ import { CategoryBreadcrumbFragment } from '../components/CategoryBreadcrumb'
4
+ import { CategoryChildrenFragment } from '../components/CategoryChildren/CategoryChildren.gql'
5
+
6
+ export type UseCategoryTreeProps = {
7
+ category?: CategoryChildrenFragment & CategoryBreadcrumbFragment
8
+ params?: ProductListParams
9
+ hideBreadcrumbs?: boolean | null
10
+ }
11
+
12
+ export type CategoryTreeItem = {
13
+ title: React.ReactNode
14
+ value: string
15
+ selected: boolean
16
+ isBack?: boolean
17
+ indent: number
18
+ uid: string
19
+ count: null | number
20
+ visible?: boolean
21
+ }
22
+
23
+ export function useCategoryTree(props: UseCategoryTreeProps): CategoryTreeItem[] | null {
24
+ const { category, params, hideBreadcrumbs } = props
25
+
26
+ if (!params || !category || !category.url_path || !category.name) return null
27
+
28
+ const parents = filterNonNullableKeys(category?.breadcrumbs, [
29
+ 'category_name',
30
+ 'category_level',
31
+ 'category_url_path',
32
+ ]).map<CategoryTreeItem>((breadcrumb) => ({
33
+ title: breadcrumb.category_name,
34
+ value: breadcrumb.category_url_path,
35
+ indent: 0,
36
+ isBack: true,
37
+ selected: params?.url === breadcrumb.category_url_path,
38
+ uid: breadcrumb.category_uid,
39
+ count: null,
40
+ }))
41
+
42
+ let children = filterNonNullableKeys(category.children, [
43
+ 'url_path',
44
+ 'name',
45
+ 'include_in_menu',
46
+ ]).map<CategoryTreeItem>((categoryItem) => ({
47
+ title: <>{`${`${categoryItem.name}`}`}</>,
48
+ value: categoryItem.url_path,
49
+ indent: hideBreadcrumbs ? 0 : 2,
50
+ isBack: false,
51
+ selected: params.url === categoryItem.url_path,
52
+ uid: categoryItem.uid,
53
+ count: null,
54
+ }))
55
+
56
+ if (!children.find((item) => item.value === category.url_path) && !hideBreadcrumbs)
57
+ children.push({
58
+ title: <> {category.name}</>,
59
+ value: category.url_path,
60
+ indent: 1,
61
+ isBack: false,
62
+ selected: true,
63
+ uid: category.uid,
64
+ count: null,
65
+ })
66
+ else if (!hideBreadcrumbs) children = children.map((child) => ({ ...child, indent: 2 }))
67
+
68
+ if (hideBreadcrumbs) return children.sort((a, b) => a.indent - b.indent)
69
+
70
+ return [...parents, ...children].sort((a, b) => a.indent - b.indent)
71
+ }