@jetshop/template-trend 5.10.0 → 5.12.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 (82) hide show
  1. package/.linaria-cache/packages/template-trend/src/components/ContentPage/ContentPage.linaria.css +5 -3
  2. package/.linaria-cache/packages/template-trend/src/components/ContentPage/SubPageNavigation.linaria.css +4 -0
  3. package/.linaria-cache/packages/template-trend/src/components/Layout/Header/ChannelSelector/ChannelSelector.linaria.css +1 -1
  4. package/.linaria-cache/packages/template-trend/src/components/StartPage/Content/StartPageCampaign.linaria.css +1 -1
  5. package/.linaria-cache/packages/template-trend/src/components/StartPage/Content/StartPageHero.linaria.css +1 -1
  6. package/.linaria-cache/packages/template-trend/src/components/StartPage/StartPage.linaria.css +0 -1
  7. package/.linaria-cache/packages/template-trend/src/components/ui/Button.linaria.css +3 -2
  8. package/.linaria-cache/packages/ui/Breadcrumbs/Breadcrumbs.linaria.css +1 -1
  9. package/.linaria-cache/packages/ui/DropdownMenu/DropdownMenu.linaria.css +1 -1
  10. package/.vscode/launch.json +11 -0
  11. package/README.md +118 -1944
  12. package/package.json +5 -5
  13. package/schema.graphql +5 -2
  14. package/src/components/Auth/ForgotPassword.js +3 -8
  15. package/src/components/Auth/README.md +5 -0
  16. package/src/components/Cart/CartButton.js +40 -44
  17. package/src/components/Cart/CartFlyout.js +18 -7
  18. package/src/components/Cart/CartItem.js +12 -15
  19. package/src/components/Cart/{addMultipleToCart.gql → queries/addMultipleToCart.gql} +1 -1
  20. package/src/components/Cart/{addToCart.gql → queries/addToCart.gql} +1 -1
  21. package/src/components/Cart/{CartFragment.gql → queries/cartFragment.gql} +2 -5
  22. package/src/components/Cart/{CartQuery.gql → queries/cartQuery.gql} +1 -1
  23. package/src/components/Cart/{decrementQuantity.gql → queries/decrementQuantity.gql} +1 -1
  24. package/src/components/Cart/{incrementQuantity.gql → queries/incrementQuantity.gql} +1 -1
  25. package/src/components/Cart/{removeFromCart.gql → queries/removeFromCart.gql} +1 -1
  26. package/src/components/CategoryPage/CategoryHeader.js +3 -3
  27. package/src/components/CategoryPage/CategoryPage.js +1 -0
  28. package/src/components/CategoryPage/ProductCard.js +4 -2
  29. package/src/components/CategoryPage/ProductGrid.js +8 -2
  30. package/src/components/CategoryPage/ProductGridWindow.js +22 -14
  31. package/src/components/CategoryPage/README.md +11 -0
  32. package/src/components/CategoryPage/StandardCategoryPage.js +2 -0
  33. package/src/components/CategoryPage/WindowedCategoryPage.js +7 -0
  34. package/src/components/ContentPage/ContentPage.js +69 -38
  35. package/src/components/ContentPage/ContentPageFragment.gql +29 -0
  36. package/src/components/ContentPage/SubPageNavigation.js +206 -0
  37. package/src/components/Layout/Footer/FooterLinks.js +6 -4
  38. package/src/components/Layout/Footer/PagesQuery.gql +9 -0
  39. package/src/components/Layout/Header/AutocompleteQuery.gql +1 -6
  40. package/src/components/Layout/Header/ChannelSelector/ChannelSelector.js +3 -0
  41. package/src/components/Layout/Header/ChannelSelector/ChannelSelectorModal.js +4 -3
  42. package/src/components/Layout/Header/ChannelSelector/Selector.js +2 -0
  43. package/src/components/Layout/Header/RecommendedChannel/RecommendedChannelSelector.js +2 -0
  44. package/src/components/LogOut.loadable.js +10 -0
  45. package/src/components/PreviewRoute.loadable.js +10 -0
  46. package/src/components/ProductList/AddToCart.js +8 -5
  47. package/src/components/ProductList/Favourite.js +2 -2
  48. package/src/components/ProductList/FavouriteCount.js +2 -2
  49. package/src/components/ProductList/Favourites.js +17 -12
  50. package/src/components/ProductList/Lister.js +44 -0
  51. package/src/components/ProductList/Product.js +5 -4
  52. package/src/components/ProductList/ProductLists.gql +8 -5
  53. package/src/components/ProductList/SelectVariant.js +6 -10
  54. package/src/components/ProductList/productListQueries.js +5 -0
  55. package/src/components/ProductPage/AddToCart/AddToCartForm.js +19 -18
  56. package/src/components/ProductPage/AddToCart/ProductToast.js +18 -7
  57. package/src/components/ProductPage/Images/ImageContainer.js +12 -1
  58. package/src/components/ProductPage/PackageProduct/PackageProduct.js +8 -6
  59. package/src/components/ProductPage/ProductInfo.js +1 -1
  60. package/src/components/ProductPage/ProductPage.js +3 -5
  61. package/src/components/ProductPage/ProductPageFragment.gql +1 -0
  62. package/src/components/ProductPage/StockStatus/WarehouseStock.js +15 -17
  63. package/src/components/ProductPage/VariantSelector.js +1 -1
  64. package/src/components/RouteQuery.gql +2 -2
  65. package/src/components/{StartPage → SearchPage}/CategoryList.js +6 -4
  66. package/src/components/SearchPage/EmptySearchResults.js +1 -1
  67. package/src/components/Shop.js +52 -76
  68. package/src/components/StartPage/Content/StartPageHero.js +12 -1
  69. package/src/components/StartPage/ContentItemFragment.gql +6 -1
  70. package/src/components/StartPage/StartPage.js +0 -13
  71. package/src/components/StartPage/StartPageProductGridFragment.gql +1 -0
  72. package/src/components/ui/Button.js +19 -1
  73. package/.linaria-cache/packages/ui/ChannelSelector/Region.linaria.css +0 -3
  74. package/src/components/StartPage/Campaign.js +0 -162
  75. package/src/components/StartPage/CampaignHeader.js +0 -101
  76. package/src/components/StartPage/ExtraDetails.js +0 -72
  77. package/src/components/StartPage/Readme.md +0 -88
  78. package/src/components/StartPage/campaign.json +0 -20
  79. package/src/components/StartPage/campaignHeader.json +0 -5
  80. package/src/components/StartPage/categoryList.json +0 -65
  81. package/src/components/StartPage/extraDetails.json +0 -6
  82. package/src/components/StartPage/title.json +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetshop/template-trend",
3
- "version": "5.10.0",
3
+ "version": "5.12.0",
4
4
  "license": "MIT",
5
5
  "scripts": {
6
6
  "build": "react-scripts build",
@@ -45,11 +45,11 @@
45
45
  ]
46
46
  },
47
47
  "dependencies": {
48
- "@jetshop/core": "^5.10.0",
48
+ "@jetshop/core": "^5.12.0",
49
49
  "@jetshop/flight-shortcodes": "^2.0.10",
50
- "@jetshop/intl": "^5.10.0",
51
- "@jetshop/react-scripts": "^5.10.0",
52
- "@jetshop/ui": "^5.10.0",
50
+ "@jetshop/intl": "^5.12.0",
51
+ "@jetshop/react-scripts": "^5.12.0",
52
+ "@jetshop/ui": "^5.12.0",
53
53
  "@react-google-maps/api": "~1.7.0",
54
54
  "prop-types": "^15.6.2",
55
55
  "react": "^16.9.0",
package/schema.graphql CHANGED
@@ -212,7 +212,10 @@ type Category implements Document {
212
212
  """
213
213
  isDynamic: Boolean!
214
214
 
215
- """Get content data set via the Content Editor"""
215
+ """
216
+ Get content data set via the Content Editor.NB: Carries a performance cost, as
217
+ asking for this will result in a separate API call in the backend.
218
+ """
216
219
  data: Content
217
220
  }
218
221
 
@@ -1356,7 +1359,7 @@ type PagedResult {
1356
1359
  result: [Product]!
1357
1360
  }
1358
1361
 
1359
- """The `Paging` scalar type represents a numeric values between (0; 100>"""
1362
+ """The `Paging` scalar type represents a numeric values between <1; 100>"""
1360
1363
  scalar Paging
1361
1364
 
1362
1365
  input PagingInput {
@@ -13,7 +13,7 @@ import { activeSegment, smallSection } from './UI/Form';
13
13
  import MaxWidth from '../Layout/MaxWidth';
14
14
  import { cx } from 'linaria';
15
15
 
16
- export default function ForgotPasswordPage(props) {
16
+ export default function ForgotPasswordPage() {
17
17
  return (
18
18
  <MaxWidth style={{ alignItems: 'center', marginTop: '2em' }}>
19
19
  <ForgotPasswordProvider>
@@ -28,13 +28,8 @@ export default function ForgotPasswordPage(props) {
28
28
  }
29
29
 
30
30
  function ForgotPasswordForm() {
31
- const {
32
- submitted,
33
- isSubmitting,
34
- globalError,
35
- isValid,
36
- emailInputProps
37
- } = useForgotPasswordData();
31
+ const { submitted, isSubmitting, globalError, isValid, emailInputProps } =
32
+ useForgotPasswordData();
38
33
 
39
34
  if (submitted) {
40
35
  return (
@@ -0,0 +1,5 @@
1
+ # Auth
2
+
3
+ These components deal with registering and signing in, using Jetshop to keep track of memberships. This is usually used for customer loyalty programs, or for e.g. b2b sales where you need an account to browse the site.
4
+
5
+ If you don't use this feature, feel free to comment out the imports and routes in Shop.js to reduce the bundle size.
@@ -1,14 +1,15 @@
1
+ import React from 'react';
2
+ import { css } from 'linaria';
3
+ import { styled } from 'linaria/react';
4
+
1
5
  import CartProvider from '@jetshop/core/components/Query/CartProvider';
2
6
  import t from '@jetshop/intl';
3
7
  import { Above } from '@jetshop/ui/Breakpoints';
4
8
  import { DrawerTrigger } from '@jetshop/ui/Modal/Drawer/DrawerTrigger';
5
9
  import { FlyoutTrigger } from '@jetshop/ui/Modal/Flyout';
6
- import { styled } from 'linaria/react';
7
- import { css } from 'linaria';
8
- import React, { Fragment } from 'react';
9
- import { ReactComponent as Cart } from '../../svg/Cart.svg';
10
+ import { ReactComponent as CartIcon } from '../../svg/Cart.svg';
10
11
  import Badge from '../ui/Badge';
11
- import cartQuery from './CartQuery.gql';
12
+ import cartQuery from './queries/cartQuery.gql';
12
13
 
13
14
  const Button = styled('button')`
14
15
  padding: 0;
@@ -38,7 +39,7 @@ function CartButton({ target, itemsInCart, className }) {
38
39
  data-testid="cart-button"
39
40
  onClick={target.isOpen ? target.hideTarget : target.showTarget}
40
41
  >
41
- <Cart className="badge-svg-wrapper" />
42
+ <CartIcon className="badge-svg-wrapper" />
42
43
  <span>{t('Cart')}</span>
43
44
  </Button>
44
45
  {itemsInCart > 0 && <Badge text={itemsInCart} />}
@@ -48,45 +49,40 @@ function CartButton({ target, itemsInCart, className }) {
48
49
 
49
50
  function CartButtonFlyout({ className }) {
50
51
  return (
51
- <Fragment>
52
- <CartProvider query={cartQuery}>
53
- {result => {
54
- // Set items in cart to the API result.
55
- // If the result is undefined, fall back to 0
56
- const itemsInCart = result?.data?.cart?.totalQuantity || 0;
52
+ <CartProvider query={cartQuery}>
53
+ {result => {
54
+ const itemsInCart = result?.data?.cart?.totalQuantity || 0;
57
55
 
58
- return (
59
- // Use a flyout for breakpoints above md
60
- // Else use a Drawer
61
- <Above breakpoint="md">
62
- {matches =>
63
- matches ? (
64
- <FlyoutTrigger id="cart-flyout">
65
- {flyout => (
66
- <CartButton
67
- className={className}
68
- target={flyout}
69
- itemsInCart={itemsInCart}
70
- />
71
- )}
72
- </FlyoutTrigger>
73
- ) : (
74
- <DrawerTrigger preventOverflow={true} id="cart-drawer">
75
- {drawer => (
76
- <CartButton
77
- className={className}
78
- target={drawer}
79
- itemsInCart={itemsInCart}
80
- />
81
- )}
82
- </DrawerTrigger>
83
- )
84
- }
85
- </Above>
86
- );
87
- }}
88
- </CartProvider>
89
- </Fragment>
56
+ // Drawer on mobile, flyout on desktop
57
+ return (
58
+ <Above breakpoint="md">
59
+ {matches =>
60
+ matches ? (
61
+ <FlyoutTrigger id="cart-flyout">
62
+ {flyout => (
63
+ <CartButton
64
+ className={className}
65
+ target={flyout}
66
+ itemsInCart={itemsInCart}
67
+ />
68
+ )}
69
+ </FlyoutTrigger>
70
+ ) : (
71
+ <DrawerTrigger preventOverflow={true} id="cart-drawer">
72
+ {drawer => (
73
+ <CartButton
74
+ className={className}
75
+ target={drawer}
76
+ itemsInCart={itemsInCart}
77
+ />
78
+ )}
79
+ </DrawerTrigger>
80
+ )
81
+ }
82
+ </Above>
83
+ );
84
+ }}
85
+ </CartProvider>
90
86
  );
91
87
  }
92
88
 
@@ -1,3 +1,6 @@
1
+ import React from 'react';
2
+ import { styled } from 'linaria/react';
3
+
1
4
  import { useTracker } from '@jetshop/core/analytics/Analytics';
2
5
  import { trackCartCheckoutEvent } from '@jetshop/core/analytics/tracking';
3
6
  import CartProvider from '@jetshop/core/components/Query/CartProvider';
@@ -6,15 +9,15 @@ import { Above } from '@jetshop/ui/Breakpoints';
6
9
  import Drawer, { DrawerTarget } from '@jetshop/ui/Modal/Drawer';
7
10
  import { FlyoutTarget } from '@jetshop/ui/Modal/Flyout';
8
11
  import { Price } from '@jetshop/ui/Price';
12
+ import { useChannelSettings } from '@jetshop/core/hooks/Channels/useChannelSettings';
13
+ import { Currency } from '@jetshop/ui/Price/Currency';
14
+
9
15
  import { theme } from '../Theme';
10
- import React from 'react';
11
- import { styled } from 'linaria/react';
12
16
  import { baseStyles } from '../ui/Button';
13
17
  import CartItem from './CartItem';
14
- import cartQuery from './CartQuery.gql';
15
18
  import FreeShipping from './FreeShipping';
16
- import { useChannelSettings } from '@jetshop/core/hooks/Channels/useChannelSettings';
17
- import { Currency } from '@jetshop/ui/Price/Currency';
19
+
20
+ import cartQuery from './queries/cartQuery.gql';
18
21
 
19
22
  const Flyout = styled('div')`
20
23
  background: white;
@@ -161,8 +164,16 @@ const CartFlyoutView = ({ result, modal, ...rest }) => {
161
164
  <Checkout
162
165
  data-testid="checkout-button"
163
166
  href={checkoutUrl}
164
- onClick={() => {
165
- track(trackCartCheckoutEvent({ cart: result.data.cart }));
167
+ onClick={event => {
168
+ event.preventDefault();
169
+ track(
170
+ trackCartCheckoutEvent({
171
+ cart: result.data.cart,
172
+ callback: () => {
173
+ window.location = checkoutUrl;
174
+ }
175
+ })
176
+ );
166
177
  }}
167
178
  >
168
179
  {t('Check out')}
@@ -1,18 +1,19 @@
1
+ import React from 'react';
2
+ import { styled } from 'linaria/react';
3
+ import { Link } from 'react-router-dom';
4
+
1
5
  import useDecrementQuantity from '@jetshop/core/components/Mutation/useDecrementQuantity';
2
6
  import useIncrementQuantity from '@jetshop/core/components/Mutation/useIncrementQuantity';
3
7
  import useRemoveFromCart from '@jetshop/core/components/Mutation/useRemoveFromCart';
4
8
  import getCartItemVariant from '@jetshop/core/helpers/getCartItemVariant';
5
9
  import Image from '@jetshop/ui/Image';
6
10
  import { Price } from '@jetshop/ui/Price';
7
- import { ReactComponent as Cross } from '@jetshop/ui/svg/Cross.svg';
8
- import React from 'react';
9
- import { styled } from 'linaria/react';
10
- import { Link } from 'react-router-dom';
11
+ import { ReactComponent as CrossIcon } from '@jetshop/ui/svg/Cross.svg';
11
12
  import { FlyoutTrigger } from '@jetshop/ui/Modal/Flyout';
12
- import removeFromCartMutation from './removeFromCart.gql';
13
- import incrementQuantityMutation from './incrementQuantity.gql';
14
- import decrementQuantityMutation from './decrementQuantity.gql';
15
- import cartQuery from './CartQuery.gql';
13
+ import removeFromCartMutation from './queries/removeFromCart.gql';
14
+ import incrementQuantityMutation from './queries/incrementQuantity.gql';
15
+ import decrementQuantityMutation from './queries/decrementQuantity.gql';
16
+ import cartQuery from './queries/cartQuery.gql';
16
17
 
17
18
  const Wrapper = styled('div')`
18
19
  display: flex;
@@ -103,12 +104,8 @@ const RemoveItem = styled('div')`
103
104
  `;
104
105
 
105
106
  const CartItem = ({ item, className = '' }) => {
106
- const {
107
- isVariant,
108
- variantImage,
109
- variantValues,
110
- hasVariantImage
111
- } = getCartItemVariant(item);
107
+ const { isVariant, variantImage, variantValues, hasVariantImage } =
108
+ getCartItemVariant(item);
112
109
 
113
110
  const { incrementQuantity } = useIncrementQuantity({
114
111
  incrementQuantityMutation,
@@ -196,7 +193,7 @@ const CartItem = ({ item, className = '' }) => {
196
193
  }
197
194
  data-testid="remove-from-cart"
198
195
  >
199
- <Cross />
196
+ <CrossIcon />
200
197
  </button>
201
198
  </RemoveItem>
202
199
 
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  mutation addMultipleToCart($cartId: String, $items: [AddMultipleToCartInput]!) {
4
4
  addMultipleToCart(cartId: $cartId, items: $items) {
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  mutation addToCart($input: AddToCartInput!) {
4
4
  addToCart(input: $input) {
@@ -4,6 +4,7 @@
4
4
  #import "@jetshop/core/data/fragments/CommentsFragment.gql"
5
5
 
6
6
  fragment Cart on Cart {
7
+ __optimistic @client
7
8
  id
8
9
  externalCheckoutUrl
9
10
  totalQuantity
@@ -81,6 +82,7 @@ fragment Cart on Cart {
81
82
  primaryRoute {
82
83
  id
83
84
  path
85
+ breadcrumbs
84
86
  }
85
87
  customFields {
86
88
  key
@@ -96,11 +98,6 @@ fragment Cart on Cart {
96
98
  title
97
99
  url
98
100
  }
99
- canonicalCategory {
100
- primaryRoute {
101
- path
102
- }
103
- }
104
101
  }
105
102
  variantOptionNames
106
103
  }
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  query CartQuery($cartId: String) {
4
4
  cart(id: $cartId) {
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  mutation decrementItemQuantity($input: ChangeByOneItemQuantityInput!) {
4
4
  decrementItemQuantity(input: $input) {
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  mutation incrementItemQuantity($input: ChangeByOneItemQuantityInput!) {
4
4
  incrementItemQuantity(input: $input) {
@@ -1,4 +1,4 @@
1
- #import "./CartFragment.gql"
1
+ #import "./cartFragment.gql"
2
2
 
3
3
  mutation removeFromCart($input: RemoveFromCartInput!) {
4
4
  removeFromCart(input: $input) {
@@ -109,12 +109,11 @@ const CategoryHeader = ({
109
109
  category,
110
110
  parents,
111
111
  imageSrc,
112
- breadcrumbs = { value: true },
112
+ breadcrumbs,
113
113
  content
114
114
  }) => {
115
- const { value } = breadcrumbs;
116
115
  const breadcrumbProps = {
117
- breadcrumbText: value ? category.breadcrumbText : '',
116
+ breadcrumbs,
118
117
  parents
119
118
  };
120
119
  const isImageBackground =
@@ -130,6 +129,7 @@ const CategoryHeader = ({
130
129
  quality={80}
131
130
  className={headerImageStyles}
132
131
  critical={true}
132
+ sizes={[1, 1, 1, 1, 1216]}
133
133
  >
134
134
  <Content
135
135
  category={category}
@@ -25,6 +25,7 @@ const CategoryPage = props => {
25
25
  const searchObject = qs.parse(search, { ignoreQueryPrefix: true });
26
26
  const standardPagination = searchObject.standardPagination === 'true';
27
27
 
28
+ // Comment out the one you're not using
28
29
  if (standardPagination) {
29
30
  return <LoadableStandardCategoryPage {...props} />;
30
31
  } else {
@@ -65,15 +65,16 @@ export function ProductCard({
65
65
  product,
66
66
  className,
67
67
  imageAspect = '1:1',
68
- imageSizes = [1 / 4, 1 / 3, 1 / 2, 1 / 2],
68
+ imageSizes = [1 / 2, 1 / 2, 1 / 3, 1 / 4],
69
69
  forwardRef,
70
70
  as = 'li',
71
71
  children,
72
+ loadImageEagerly = false,
72
73
  ...linkProps
73
74
  }) {
74
75
  const hasImages = product.images && product.images.length > 0;
75
76
  const Tag = as;
76
- let badges = [...product.badges];
77
+ let badges = [...(product.badges || [])];
77
78
  product.isPackage &&
78
79
  badges.push({
79
80
  location: 'TOP_RIGHT',
@@ -103,6 +104,7 @@ export function ProductCard({
103
104
  src={product.images[0].url}
104
105
  modifiedDate={product.images[0].modifiedDate}
105
106
  badges={<Badges badges={badges} />}
107
+ critical={loadImageEagerly}
106
108
  ></Image>
107
109
  ) : (
108
110
  <Image src={transparentDataImg} />
@@ -51,9 +51,14 @@ export const Wrapper = styled('ul')`
51
51
  }
52
52
  `;
53
53
 
54
+ export function isAboveFold(index) {
55
+ return index < 4;
56
+ }
57
+
54
58
  export function ProductGrid({
55
59
  products,
56
60
  listName,
61
+ category = '',
57
62
  loading,
58
63
  className,
59
64
  ...rest
@@ -64,8 +69,8 @@ export function ProductGrid({
64
69
  if (!products || products.length === 0) return;
65
70
 
66
71
  // Otherwise track a list view event
67
- track(trackListEvent({ listName, products }));
68
- }, [listName, products, track]);
72
+ track(trackListEvent({ listName, products, category }));
73
+ }, [listName, products, track, category]);
69
74
 
70
75
  if (!products) return null;
71
76
 
@@ -81,6 +86,7 @@ export function ProductGrid({
81
86
  product={product}
82
87
  style={{ opacity: loading ? 0.5 : 1 }}
83
88
  list={listName}
89
+ loadImageEagerly={isAboveFold(index)}
84
90
  {...rest}
85
91
  >
86
92
  <Favourite
@@ -3,7 +3,7 @@ import { trackListEvent } from '@jetshop/core/analytics/tracking';
3
3
  import React, { useEffect, useMemo } from 'react';
4
4
  import { css, cx } from 'linaria';
5
5
  import { ProductCard } from './ProductCard';
6
- import { priceStyle } from './ProductGrid';
6
+ import { isAboveFold, priceStyle } from './ProductGrid';
7
7
  import { WindowGrid } from '@jetshop/ui/WindowGrid';
8
8
 
9
9
  const container = css`
@@ -27,6 +27,7 @@ function ProductGridWindow({
27
27
  prevOffset,
28
28
  itemsPerRow,
29
29
  categoryPath,
30
+ category = '',
30
31
  ...rest
31
32
  }) {
32
33
  // Track product listing
@@ -36,28 +37,35 @@ function ProductGridWindow({
36
37
  if (!products || products.length === 0) return;
37
38
 
38
39
  // Otherwise track a list view event
39
- track(trackListEvent({ listName, products }));
40
- }, [listName, products, track]);
40
+ track(trackListEvent({ listName, products, category }));
41
+ }, [listName, products, track, category]);
41
42
 
42
43
  const renderProduct = useMemo(
43
- () => ({ item: product, style, innerRef }) => (
44
- <div className={defaultStyle} style={style} ref={innerRef}>
45
- <ProductCard
46
- key={product.articleNumber}
47
- product={product}
48
- as="div"
49
- categoryPath={categoryPath}
50
- />
51
- </div>
52
- ),
44
+ () =>
45
+ ({ item: product, style, innerRef }) =>
46
+ (
47
+ <div className={defaultStyle} style={style} ref={innerRef}>
48
+ <ProductCard
49
+ key={product.articleNumber}
50
+ product={product}
51
+ as="div"
52
+ categoryPath={categoryPath}
53
+ loadImageEagerly={isAboveFold(product.index)}
54
+ />
55
+ </div>
56
+ ),
53
57
  [categoryPath]
54
58
  );
55
59
 
60
+ const items = useMemo(() => {
61
+ return products.map((product, index) => ({ ...product, index }));
62
+ }, [products]);
63
+
56
64
  return (
57
65
  <WindowGrid
58
66
  id={id}
59
67
  itemsPerRow={[2, null, 3, 4]}
60
- items={products}
68
+ items={items}
61
69
  prevOffset={prevOffset}
62
70
  className={cx(container, priceStyle)}
63
71
  component={renderProduct}
@@ -0,0 +1,11 @@
1
+ # Category page
2
+ This folder contains two versions of category pages, of which you would usually select one.
3
+
4
+ ## Classic paginated category page
5
+ A category page that uses classic pagination, meaning next/previous buttons to step through pages, showing only one page of products at a time.
6
+
7
+ ## Infinite pagination category page
8
+ A more scroll-friendly version of a category page, where new products are appended to the list when you press the "Load more products" button. In order not to lose performance when rendering a large amount of products, it uses a technique called windowing to only render the products that are in view at the moment. This can cause issues if you have product cards of varying height, so make sure that all images and details showed on the product card result in the same overall height for the product card.
9
+
10
+ ## Read more
11
+ You can find more information about pagination in the [Flight documentation](https://docs.dev.jetshop.se/pagination).
@@ -44,6 +44,7 @@ const Category = ({ category, result }) => {
44
44
  <CategoryHeader
45
45
  category={category}
46
46
  parents={result?.data?.route?.parents}
47
+ breadcrumbs={result?.data?.route?.breadcrumbs}
47
48
  />
48
49
 
49
50
  <Container>
@@ -63,6 +64,7 @@ const Category = ({ category, result }) => {
63
64
  products={category.products.result}
64
65
  listName={category.name}
65
66
  categoryPath={category.isDynamic ? null : result?.data?.route}
67
+ category={result?.data?.route?.breadcrumbs?.join('/') || ''}
66
68
  loading={result.loading}
67
69
  imageSizes={[1 / 2, 1 / 2, 1 / 3, 1 / 4]}
68
70
  />
@@ -78,6 +78,11 @@ const WindowedCategory = ({ category, result }) => {
78
78
  category={category}
79
79
  parents={result?.data?.route?.parents}
80
80
  {...props}
81
+ breadcrumbs={
82
+ props.breadcrumbs?.value
83
+ ? result?.data?.route?.breadcrumbs
84
+ : []
85
+ }
81
86
  />
82
87
  </div>
83
88
  )
@@ -89,6 +94,7 @@ const WindowedCategory = ({ category, result }) => {
89
94
  <CategoryHeader
90
95
  category={category}
91
96
  parents={result?.data?.route?.parents}
97
+ breadcrumbs={result?.data?.route?.breadcrumbs}
92
98
  />
93
99
  )}
94
100
  <Container>
@@ -130,6 +136,7 @@ const WindowedCategory = ({ category, result }) => {
130
136
  products={products}
131
137
  listName={category.name}
132
138
  categoryPath={categoryPath}
139
+ category={result?.data?.route?.breadcrumbs?.join('/') || ''}
133
140
  loading={result.loading}
134
141
  imageSizes={[1 / 2, 1 / 2, 1 / 3, 1 / 4]}
135
142
  />