@akinon/projectzero 1.73.0-rc.8 → 1.73.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.
@@ -26,8 +26,7 @@ const withPwaConfig = withPWA({
26
26
 
27
27
  const sentryConfig = {
28
28
  silent: true,
29
- dryRun: !process.env.SENTRY_DSN,
30
- hideSourceMaps: true
29
+ dryRun: !process.env.SENTRY_DSN
31
30
  };
32
31
 
33
32
  const enhancedConfig = withPzConfig(nextConfig);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.73.0-rc.8",
3
+ "version": "1.73.0",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,25 +22,25 @@
22
22
  "prestart": "pz-prestart"
23
23
  },
24
24
  "dependencies": {
25
- "@akinon/next": "1.73.0-rc.8",
26
- "@akinon/pz-akifast": "1.73.0-rc.8",
27
- "@akinon/pz-b2b": "1.73.0-rc.8",
28
- "@akinon/pz-basket-gift-pack": "1.73.0-rc.8",
29
- "@akinon/pz-bkm": "1.73.0-rc.8",
30
- "@akinon/pz-checkout-gift-pack": "1.73.0-rc.8",
31
- "@akinon/pz-click-collect": "1.73.0-rc.8",
32
- "@akinon/pz-credit-payment": "1.73.0-rc.8",
33
- "@akinon/pz-gpay": "1.73.0-rc.8",
34
- "@akinon/pz-masterpass": "1.73.0-rc.8",
35
- "@akinon/pz-one-click-checkout": "1.73.0-rc.8",
36
- "@akinon/pz-otp": "1.73.0-rc.8",
37
- "@akinon/pz-pay-on-delivery": "1.73.0-rc.8",
38
- "@akinon/pz-saved-card": "1.73.0-rc.8",
39
- "@akinon/pz-tabby-extension": "1.73.0-rc.8",
25
+ "@akinon/next": "1.73.0",
26
+ "@akinon/pz-akifast": "1.73.0",
27
+ "@akinon/pz-b2b": "1.73.0",
28
+ "@akinon/pz-basket-gift-pack": "1.73.0",
29
+ "@akinon/pz-bkm": "1.73.0",
30
+ "@akinon/pz-checkout-gift-pack": "1.73.0",
31
+ "@akinon/pz-click-collect": "1.73.0",
32
+ "@akinon/pz-credit-payment": "1.73.0",
33
+ "@akinon/pz-gpay": "1.73.0",
34
+ "@akinon/pz-masterpass": "1.73.0",
35
+ "@akinon/pz-one-click-checkout": "1.73.0",
36
+ "@akinon/pz-otp": "1.73.0",
37
+ "@akinon/pz-pay-on-delivery": "1.73.0",
38
+ "@akinon/pz-saved-card": "1.73.0",
39
+ "@akinon/pz-tabby-extension": "1.73.0",
40
40
  "@hookform/resolvers": "2.9.0",
41
41
  "@next/third-parties": "14.1.0",
42
42
  "@react-google-maps/api": "2.17.1",
43
- "@sentry/nextjs": "8.35.0",
43
+ "@sentry/nextjs": "7.116.0",
44
44
  "dayjs": "1.11.5",
45
45
  "lossless-json": "2.0.5",
46
46
  "next": "14.2.5",
@@ -60,7 +60,7 @@
60
60
  "yup": "0.32.11"
61
61
  },
62
62
  "devDependencies": {
63
- "@akinon/eslint-plugin-projectzero": "1.73.0-rc.8",
63
+ "@akinon/eslint-plugin-projectzero": "1.73.0",
64
64
  "@semantic-release/changelog": "6.0.2",
65
65
  "@semantic-release/exec": "6.0.3",
66
66
  "@semantic-release/git": "10.0.1",
@@ -75,7 +75,7 @@
75
75
  "@types/react-dom": "18.2.12",
76
76
  "@typescript-eslint/eslint-plugin": "6.7.4",
77
77
  "@typescript-eslint/parser": "6.7.4",
78
- "autoprefixer": "10.4.20",
78
+ "autoprefixer": "10.4.13",
79
79
  "client-only": "0.0.1",
80
80
  "clsx": "1.1.1",
81
81
  "currency-symbol-map": "5.1.0",
@@ -96,7 +96,7 @@
96
96
  "stylelint-config-standard": "25.0.0",
97
97
  "stylelint-scss": "4.2.0",
98
98
  "stylelint-selector-bem-pattern": "2.1.1",
99
- "tailwindcss": "3.4.14",
99
+ "tailwindcss": "3.4.12",
100
100
  "ts-jest": "29.1.1",
101
101
  "ts-node": "10.7.0",
102
102
  "typescript": "5.2.2"
@@ -0,0 +1,3 @@
1
+ import { initSentry } from '@akinon/next/sentry';
2
+
3
+ initSentry('Edge');
@@ -0,0 +1,3 @@
1
+ import { initSentry } from '@akinon/next/sentry';
2
+
3
+ initSentry('Server');
@@ -1,14 +1,87 @@
1
- import { BasketContent } from '@theme/views/basket/basket-content';
2
- import { getBasketData } from '@akinon/next/data/server/basket';
1
+ 'use client';
2
+
3
+ import { useEffect } from 'react';
4
+ import { ROUTES } from '@theme/routes';
5
+ import { useGetBasketQuery } from '@akinon/next/data/client/basket';
6
+ import { pushCartView } from '@theme/utils/gtm';
7
+ import { Button, LoaderSpinner, Link } from '@theme/components';
8
+ import { BasketItem, Summary } from '@theme/views/basket';
9
+ import { useLocalization } from '@akinon/next/hooks';
10
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
3
11
  import settings from '@theme/settings';
4
12
 
5
- export default async function Page() {
6
- const { basket } = await getBasketData();
13
+ export default function Page() {
14
+ const { data: basket, isLoading, isSuccess } = useGetBasketQuery();
15
+ const { t } = useLocalization();
16
+ const multiBasket = settings.plugins?.multiBasket ?? false;
17
+
18
+ useEffect(() => {
19
+ if (isSuccess) {
20
+ const products = basket.basketitem_set.map((basketItem) => ({
21
+ ...basketItem.product
22
+ }));
23
+ pushCartView(products);
24
+ }
25
+ }, [basket, isSuccess]);
26
+
27
+ return (
28
+ <div className="max-w-screen-xl p-4 flex flex-col text-primary-800 lg:p-8 xl:flex-row xl:mx-auto">
29
+ {isLoading && (
30
+ <div className="flex justify-center w-full">
31
+ <LoaderSpinner />
32
+ </div>
33
+ )}
34
+ {isSuccess &&
35
+ (basket && basket.basketitem_set && basket.basketitem_set.length > 0 ? (
36
+ <>
37
+ <div className="flex-1 xl:mr-16">
38
+ <div className="flex items-center justify-between py-2 border-b border-gray-200 lg:py-3">
39
+ <h2 className="text-xl lg:text-2xl font-light">
40
+ {t('basket.my_cart')}
41
+ </h2>
42
+ <Link
43
+ href={ROUTES.HOME}
44
+ className="text-xs hover:text-secondary-500"
45
+ >
46
+ {t('basket.back_to_shopping')}
47
+ </Link>
48
+ </div>
49
+ <ul>
50
+ {multiBasket ? (
51
+ <PluginModule
52
+ component={Component.MultiBasket}
53
+ props={{ BasketItem }}
54
+ />
55
+ ) : (
56
+ basket.basketitem_set.map((basketItem, index) => (
57
+ <BasketItem basketItem={basketItem} key={index} />
58
+ ))
59
+ )}
60
+ </ul>
61
+ </div>
62
+ <Summary basket={basket} />
63
+ </>
64
+ ) : (
65
+ <div className="flex flex-col items-center container max-w-screen-sm py-4 px-4 xs:py-6 xs:px-6 sm:py-8 sm:px-8 lg:max-w-screen-xl">
66
+ <h1
67
+ className="w-full text-xl font-light text-secondary text-center sm:text-2xl"
68
+ data-testid="basket-empty"
69
+ >
70
+ {t('basket.empty.title')}
71
+ </h1>
7
72
 
8
- const multiBasket: boolean =
9
- typeof settings.plugins?.multiBasket === 'boolean'
10
- ? settings.plugins.multiBasket
11
- : false;
73
+ <div className="w-full text-sm text-black-800 text-center my-4 mb-2 sm:text-base">
74
+ <p>{t('basket.empty.content_first')}</p>
75
+ <p>{t('basket.empty.content_second')}.</p>
76
+ </div>
12
77
 
13
- return <BasketContent initialBasket={basket} multiBasket={multiBasket} />;
78
+ <Link href={ROUTES.HOME} passHref>
79
+ <Button className="px-10 mt-2" appearance="filled">
80
+ {t('basket.empty.button')}
81
+ </Button>
82
+ </Link>
83
+ </div>
84
+ ))}
85
+ </div>
86
+ );
14
87
  }
@@ -1,8 +1,8 @@
1
- import { MouseEvent, useCallback, useEffect, useState } from 'react';
1
+ import { useCallback, useEffect, useState } from 'react';
2
2
  import { PaginationProps } from '@theme/components/types';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import clsx from 'clsx';
5
- import { Link, Button, LoaderSpinner } from '@theme/components';
5
+ import { Button } from '@theme/components';
6
6
  import usePagination from '@akinon/next/hooks/use-pagination';
7
7
  import { useLocalization } from '@akinon/next/hooks';
8
8
  import { useRouter } from '@akinon/next/hooks';
@@ -25,8 +25,7 @@ export const Pagination = (props: PaginationProps) => {
25
25
  type = 'list',
26
26
  onPageChange,
27
27
  direction,
28
- render,
29
- isLoading
28
+ render
30
29
  } = props;
31
30
 
32
31
  const pagination = usePagination(total, limit, currentPage, numberOfPages);
@@ -93,9 +92,7 @@ export const Pagination = (props: PaginationProps) => {
93
92
  }
94
93
  }, [numberOfPages, page, pageList, threshold]);
95
94
 
96
- const handleClick = (e: MouseEvent<HTMLAnchorElement>, url: string) => {
97
- e.preventDefault();
98
-
95
+ const handleClick = (url: string) => {
99
96
  const newUrl = new URL(url, window.location.origin);
100
97
  const page = newUrl.searchParams.get('page');
101
98
 
@@ -120,13 +117,6 @@ export const Pagination = (props: PaginationProps) => {
120
117
  onPageChange(changingPage);
121
118
  };
122
119
 
123
- useEffect(() => {
124
- if (type === 'infinite' && page === 1) {
125
- setPrevPage(1);
126
- setNextPage(1);
127
- }
128
- }, [page]);
129
-
130
120
  useEffect(() => {
131
121
  if (inView) {
132
122
  handlePageChange();
@@ -137,7 +127,7 @@ export const Pagination = (props: PaginationProps) => {
137
127
  if (type === 'list') {
138
128
  createListItems();
139
129
  }
140
- }, [page]); // eslint-disable-line react-hooks/exhaustive-deps
130
+ }, [createListItems, type]);
141
131
 
142
132
  useEffect(() => {
143
133
  if (total && total !== paginationTotal) {
@@ -157,23 +147,21 @@ export const Pagination = (props: PaginationProps) => {
157
147
 
158
148
  return direction === 'prev' && type !== 'list' ? (
159
149
  <>
160
- <div className="flex items-center justify-center">
161
- <Button
162
- className={twMerge('px-5', moreButtonClassName)}
163
- onClick={() => handlePageChange()}
164
- >
165
- {isLoading ? (
166
- <LoaderSpinner className="h-4 w-4" />
167
- ) : (
168
- t('category.pagination.load_previous_page')
169
- )}
170
- </Button>
171
- </div>
150
+ {Number(prevPage) !== 1 && (
151
+ <div className="flex justify-center items-center">
152
+ <Button
153
+ className={twMerge('px-5', moreButtonClassName)}
154
+ onClick={() => handlePageChange()}
155
+ >
156
+ {t('category.pagination.load_previous_page')}
157
+ </Button>
158
+ </div>
159
+ )}
172
160
  </>
173
161
  ) : (
174
162
  <>
175
163
  {type === 'more' && (
176
- <div className="flex items-center justify-center">
164
+ <div className="flex justify-center items-center">
177
165
  <Button
178
166
  className={twMerge(
179
167
  'px-5',
@@ -185,11 +173,7 @@ export const Pagination = (props: PaginationProps) => {
185
173
  onClick={() => handlePageChange()}
186
174
  disabled={Number(nextPage) === Number(last)}
187
175
  >
188
- {isLoading ? (
189
- <LoaderSpinner className="h-4 w-4" />
190
- ) : (
191
- t('category.pagination.more')
192
- )}
176
+ {t('category.pagination.more')}
193
177
  </Button>
194
178
  </div>
195
179
  )}
@@ -199,9 +183,8 @@ export const Pagination = (props: PaginationProps) => {
199
183
  )}
200
184
 
201
185
  {(type === 'infinite' || type === 'more') &&
202
- Number(nextPage) === last &&
203
- !isLoading && (
204
- <p className="mt-8 text-center">
186
+ Number(nextPage) === last && (
187
+ <p className="text-center mt-8">
205
188
  {t('category.pagination.shown_items')}
206
189
  </p>
207
190
  )}
@@ -209,37 +192,35 @@ export const Pagination = (props: PaginationProps) => {
209
192
  {type === 'list' && (
210
193
  <ul
211
194
  className={twMerge(
212
- 'mb-4 mt-8 flex items-center justify-center',
195
+ 'flex mt-8 mb-4 justify-center items-center',
213
196
  containerClassName
214
197
  )}
215
198
  >
216
199
  {prev && currentPage !== 1 && (
217
200
  <li>
218
- <Link
219
- onClick={(e) => handleClick(e, prev)}
220
- href={prev}
201
+ <button
202
+ onClick={() => handleClick(prev)}
221
203
  className={twMerge(
222
- 'flex cursor-pointer px-2 text-sm items-center',
204
+ 'flex cursor-pointer text-sm px-2',
223
205
  prevClassName
224
206
  )}
225
207
  >
226
208
  <span>&lt;</span>
227
- <span className="ms-4 hidden lg:inline-block">
209
+ <span className="hidden lg:inline-block ms-4">
228
210
  {t('category.pagination.previous')}
229
211
  </span>
230
- </Link>
212
+ </button>
231
213
  </li>
232
214
  )}
233
215
 
234
216
  {paginationItems.map((item, i) => (
235
217
  <li key={i}>
236
218
  {item?.url != '#' ? (
237
- <Link
238
- onClick={(e) => handleClick(e, item.url)}
239
- href={item.url}
219
+ <button
220
+ onClick={() => handleClick(item.url)}
240
221
  className={twMerge(
241
222
  clsx(
242
- 'cursor-pointer px-2 text-xs items-center',
223
+ 'text-xs px-2 cursor-pointer',
243
224
  { 'pointer-events-none': item.url === null },
244
225
  Number(page) === Number(item?.page)
245
226
  ? 'font-semibold text-black-800'
@@ -249,9 +230,9 @@ export const Pagination = (props: PaginationProps) => {
249
230
  )}
250
231
  >
251
232
  {item?.page}
252
- </Link>
233
+ </button>
253
234
  ) : (
254
- <span className="flex cursor-default items-center justify-center text-xs">
235
+ <span className="cursor-default text-xs flex items-center justify-center">
255
236
  {item?.page}
256
237
  </span>
257
238
  )}
@@ -260,19 +241,18 @@ export const Pagination = (props: PaginationProps) => {
260
241
 
261
242
  {showNext && (
262
243
  <li>
263
- <Link
264
- onClick={(e) => handleClick(e, next)}
265
- href={next}
244
+ <button
245
+ onClick={() => handleClick(next)}
266
246
  className={twMerge(
267
- 'flex cursor-pointer px-2 text-xs items-center',
247
+ 'flex cursor-pointer text-xs px-2',
268
248
  nextClassName
269
249
  )}
270
250
  >
271
- <span className="me-4 hidden lg:inline-block">
251
+ <span className="hidden lg:inline-block me-4">
272
252
  {t('category.pagination.next')}
273
253
  </span>
274
254
  <span>&gt;</span>
275
- </Link>
255
+ </button>
276
256
  </li>
277
257
  )}
278
258
  </ul>
@@ -23,7 +23,6 @@ export interface PaginationProps {
23
23
  type?: 'infinite' | 'list' | 'more';
24
24
  onPageChange?: (page: number) => void;
25
25
  direction?: 'next' | 'prev';
26
- isLoading?: boolean;
27
26
  }
28
27
 
29
28
  export type FileInputProps = React.HTMLProps<HTMLInputElement>;
@@ -1,24 +1,16 @@
1
1
  const { LocaleUrlStrategy } = require('@akinon/next/localization');
2
2
  const { ROUTES } = require('@theme/routes');
3
3
 
4
- /* IMPORTANT *
5
- * In order to use one locale in the locales array and hide the default locale in the URL, you need to set the localeUrlStrategy to LocaleUrlStrategy.ShowAllLocales.
6
- */
7
-
8
4
  const commerceUrl = encodeURI(process.env.SERVICE_BACKEND_URL ?? 'default');
9
5
 
10
6
  /** @type {import('@akinon/next/types').Settings} */
11
7
  module.exports = {
12
- webVitals: {
13
- enabled: true
14
- },
15
8
  commerceUrl,
16
9
  commonProductAttributes: [
17
10
  { translationKey: 'color', key: 'color' },
18
11
  { translationKey: 'size', key: 'size' }
19
12
  ],
20
13
  localization: {
21
- // If there is one locale in the locales array, the default locale will be hidden in the URL.
22
14
  locales: [
23
15
  {
24
16
  label: 'EN',
@@ -46,7 +38,7 @@ module.exports = {
46
38
  }
47
39
  ],
48
40
  defaultLocaleValue: 'en',
49
- localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale, // If there is one locale in the locales array, the default locale will be hidden in the URL and localeUrlStrategy should be set to LocaleUrlStrategy.ShowAllLocales.
41
+ localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
50
42
  redirectToDefaultLocale: true,
51
43
  defaultCurrencyCode: 'usd'
52
44
  },
@@ -3,7 +3,7 @@ import {
3
3
  useUpdateQuantityMutation
4
4
  } from '@akinon/next/data/client/basket';
5
5
  import { useAppDispatch } from '@akinon/next/redux/hooks';
6
- import { Basket, BasketItem as BasketItemType } from '@akinon/next/types';
6
+ import { BasketItem as BasketItemType } from '@akinon/next/types';
7
7
  import { Price, Button, Icon, Modal, Select, Link } from '@theme/components';
8
8
  import { useState } from 'react';
9
9
  import { useAddFavoriteMutation } from '@akinon/next/data/client/wishlist';
@@ -19,12 +19,11 @@ import { pushRemoveFromCart } from '@theme/utils/gtm';
19
19
  interface Props {
20
20
  basketItem?: BasketItemType;
21
21
  namespace?: string;
22
- onBasketUpdate?: (basket: Basket) => void;
23
22
  }
24
23
 
25
24
  export const BasketItem = (props: Props) => {
26
25
  const { t } = useLocalization();
27
- const { basketItem, namespace, onBasketUpdate } = props;
26
+ const { basketItem, namespace } = props;
28
27
  const [updateQuantityMutation] = useUpdateQuantityMutation();
29
28
  const dispatch = useAppDispatch();
30
29
  const [isRemoveBasketModalOpen, setRemoveBasketModalOpen] = useState(false);
@@ -50,21 +49,19 @@ export const BasketItem = (props: Props) => {
50
49
  requestParams.namespace = namespace;
51
50
  }
52
51
 
53
- try {
54
- const response = await updateQuantityMutation(requestParams).unwrap();
55
- dispatch(
56
- basketApi.util.updateQueryData(
57
- 'getBasket',
58
- undefined,
59
- (draftBasket) => {
60
- Object.assign(draftBasket, response.basket);
61
- }
52
+ await updateQuantityMutation(requestParams)
53
+ .unwrap()
54
+ .then((data) =>
55
+ dispatch(
56
+ basketApi.util.updateQueryData(
57
+ 'getBasket',
58
+ undefined,
59
+ (draftBasket) => {
60
+ Object.assign(draftBasket, data.basket);
61
+ }
62
+ )
62
63
  )
63
64
  );
64
- onBasketUpdate?.(response.basket);
65
- } catch (error) {
66
- console.error('Error updating quantity:', error);
67
- }
68
65
  };
69
66
 
70
67
  const deleteProduct = async (productPk?: number) => {
@@ -18,7 +18,6 @@ import clsx from 'clsx';
18
18
 
19
19
  interface Props {
20
20
  basket: Basket;
21
- onBasketUpdate?: (basket: Basket) => void;
22
21
  }
23
22
 
24
23
  const voucherCodeFormSchema = (t) =>
@@ -28,7 +27,7 @@ const voucherCodeFormSchema = (t) =>
28
27
 
29
28
  export const Summary = (props: Props) => {
30
29
  const { t } = useLocalization();
31
- const { basket, onBasketUpdate } = props;
30
+ const { basket } = props;
32
31
  const router = useRouter();
33
32
  const {
34
33
  register,
@@ -54,7 +53,7 @@ export const Summary = (props: Props) => {
54
53
  const removeVoucherCode = () => {
55
54
  removeVoucherCodeMutation()
56
55
  .unwrap()
57
- .then((basket) => {
56
+ .then((basket) =>
58
57
  dispatch(
59
58
  basketApi.util.updateQueryData(
60
59
  'getBasket',
@@ -63,9 +62,8 @@ export const Summary = (props: Props) => {
63
62
  Object.assign(draftBasket, basket);
64
63
  }
65
64
  )
66
- );
67
- onBasketUpdate?.(basket);
68
- })
65
+ )
66
+ )
69
67
  .catch((error: Error) => {
70
68
  setError('voucherCode', { message: error.data.non_field_errors });
71
69
  });
@@ -76,7 +74,7 @@ export const Summary = (props: Props) => {
76
74
  voucher_code: data.voucherCode
77
75
  })
78
76
  .unwrap()
79
- .then((basket) => {
77
+ .then((basket) =>
80
78
  dispatch(
81
79
  basketApi.util.updateQueryData(
82
80
  'getBasket',
@@ -85,9 +83,8 @@ export const Summary = (props: Props) => {
85
83
  Object.assign(draftBasket, basket);
86
84
  }
87
85
  )
88
- );
89
- onBasketUpdate?.(basket);
90
- })
86
+ )
87
+ )
91
88
  .catch((error: Error) => {
92
89
  setError('voucherCode', { message: error.data.non_field_errors });
93
90
  });
@@ -70,9 +70,9 @@ const CategoryActiveFilters = () => {
70
70
  return (
71
71
  <div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-2 mb-4">
72
72
  {facets.map((facet) =>
73
- facet?.data?.choices
74
- ?.filter((choice) => choice.is_selected)
75
- ?.map(
73
+ facet.data.choices
74
+ .filter((choice) => choice.is_selected)
75
+ .map(
76
76
  (choice) =>
77
77
  Number(choice.real_depth) !== 2 && (
78
78
  <div
@@ -112,7 +112,7 @@ export const FilterItem = ({ facet, isPending, startTransition }: Props) => {
112
112
  };
113
113
 
114
114
  const Component = getComponentByWidgetType(facet.widget_type, facet.key);
115
- const choices = sortChoices(facet?.key, [...(facet?.data?.choices || [])]);
115
+ const choices = sortChoices(facet.key, [...facet.data.choices]);
116
116
 
117
117
  return (
118
118
  <Accordion
@@ -24,7 +24,7 @@ export const Filters = (props: Props) => {
24
24
 
25
25
  const haveFilter = useMemo(() => {
26
26
  return facets.some((facet) =>
27
- facet?.data?.choices?.some((choice) => choice.is_selected)
27
+ facet.data.choices.some((choice) => choice.is_selected)
28
28
  );
29
29
  }, [facets]);
30
30
 
@@ -17,7 +17,7 @@ export default async function Layout({
17
17
  <>
18
18
  <div
19
19
  className={clsx(
20
- data?.category?.attributes?.category_banner
20
+ data.category?.attributes?.category_banner
21
21
  ? 'relative w-full'
22
22
  : 'container px-4 mx-auto lg:px-0 lg:my-4'
23
23
  )}
@@ -26,13 +26,13 @@ export default async function Layout({
26
26
  <div
27
27
  className={clsx(
28
28
  'my-4 lg:mt-7',
29
- data?.category?.attributes?.category_banner &&
29
+ data.category?.attributes?.category_banner &&
30
30
  'lg:absolute lg:inset-x-0 z-10 container lg:my-4 mx-auto'
31
31
  )}
32
32
  >
33
33
  <Breadcrumb breadcrumbList={breadcrumbData} />
34
34
  </div>
35
- <CategoryBanner {...data?.category?.attributes?.category_banner} />
35
+ <CategoryBanner {...data.category?.attributes?.category_banner} />
36
36
  </div>
37
37
  <ListPage data={data} />
38
38
  </>