@akinon/projectzero 1.82.0-rc.9 → 1.83.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.
@@ -3,4 +3,4 @@
3
3
  /// <reference types="next/navigation-types/compat/navigation" />
4
4
 
5
5
  // NOTE: This file should not be edited
6
- // see https://nextjs.org/docs/basic-features/typescript for more information.
6
+ // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.82.0-rc.9",
3
+ "version": "1.83.0",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,29 +22,29 @@
22
22
  "prestart": "pz-prestart"
23
23
  },
24
24
  "dependencies": {
25
- "@akinon/next": "1.82.0-rc.9",
26
- "@akinon/pz-akifast": "1.82.0-rc.9",
27
- "@akinon/pz-b2b": "1.82.0-rc.9",
28
- "@akinon/pz-basket-gift-pack": "1.82.0-rc.9",
29
- "@akinon/pz-bkm": "1.82.0-rc.9",
30
- "@akinon/pz-checkout-gift-pack": "1.82.0-rc.9",
31
- "@akinon/pz-click-collect": "1.82.0-rc.9",
32
- "@akinon/pz-credit-payment": "1.82.0-rc.9",
33
- "@akinon/pz-gpay": "1.82.0-rc.9",
34
- "@akinon/pz-masterpass": "1.82.0-rc.9",
35
- "@akinon/pz-one-click-checkout": "1.82.0-rc.9",
36
- "@akinon/pz-otp": "1.82.0-rc.9",
37
- "@akinon/pz-pay-on-delivery": "1.82.0-rc.9",
38
- "@akinon/pz-saved-card": "1.82.0-rc.9",
39
- "@akinon/pz-tabby-extension": "1.82.0-rc.9",
40
- "@akinon/pz-tamara-extension": "1.82.0-rc.9",
25
+ "@akinon/next": "1.83.0",
26
+ "@akinon/pz-akifast": "1.83.0",
27
+ "@akinon/pz-b2b": "1.83.0",
28
+ "@akinon/pz-basket-gift-pack": "1.83.0",
29
+ "@akinon/pz-bkm": "1.83.0",
30
+ "@akinon/pz-checkout-gift-pack": "1.83.0",
31
+ "@akinon/pz-click-collect": "1.83.0",
32
+ "@akinon/pz-credit-payment": "1.83.0",
33
+ "@akinon/pz-gpay": "1.83.0",
34
+ "@akinon/pz-masterpass": "1.83.0",
35
+ "@akinon/pz-one-click-checkout": "1.83.0",
36
+ "@akinon/pz-otp": "1.83.0",
37
+ "@akinon/pz-pay-on-delivery": "1.83.0",
38
+ "@akinon/pz-saved-card": "1.83.0",
39
+ "@akinon/pz-tabby-extension": "1.83.0",
40
+ "@akinon/pz-tamara-extension": "1.83.0",
41
41
  "@hookform/resolvers": "2.9.0",
42
42
  "@next/third-parties": "14.1.0",
43
43
  "@react-google-maps/api": "2.17.1",
44
- "@sentry/nextjs": "8.35.0",
44
+ "@sentry/nextjs": "7.116.0",
45
45
  "dayjs": "1.11.5",
46
46
  "lossless-json": "2.0.5",
47
- "next": "14.2.5",
47
+ "next": "14.2.25",
48
48
  "next-auth": "4.24.5",
49
49
  "next-pwa": "5.6.0",
50
50
  "pino": "8.11.0",
@@ -62,7 +62,7 @@
62
62
  "yup": "0.32.11"
63
63
  },
64
64
  "devDependencies": {
65
- "@akinon/eslint-plugin-projectzero": "1.82.0-rc.9",
65
+ "@akinon/eslint-plugin-projectzero": "1.83.0",
66
66
  "@semantic-release/changelog": "6.0.2",
67
67
  "@semantic-release/exec": "6.0.3",
68
68
  "@semantic-release/git": "10.0.1",
@@ -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
  }
@@ -3,38 +3,10 @@
3
3
  import { useLocalization } from '@akinon/next/hooks';
4
4
  import { Link } from '@theme/components';
5
5
  import { ROUTES } from '@theme/routes';
6
- import { useEffect } from 'react';
7
- import * as Sentry from '@sentry/nextjs';
8
- import { ClientLogType } from '@akinon/next/sentry';
9
6
 
10
- export default function ErrorPage({
11
- error,
12
- reset
13
- }: {
14
- error: Error & { digest?: string };
15
- reset: () => void;
16
- }) {
7
+ export default function Error() {
17
8
  const { t } = useLocalization();
18
9
 
19
- useEffect(() => {
20
- Sentry.withScope(function (scope) {
21
- scope.setLevel('fatal');
22
- scope.setTags({
23
- APP_TYPE: 'ProjectZeroNext',
24
- TYPE: 'Client',
25
- LOG_TYPE: ClientLogType.UNCAUGHT_ERROR_PAGE
26
- });
27
- scope.setExtra('error', error);
28
-
29
- const error_ = new Error('FATAL: Uncaught client error');
30
- error_.name = 'UNCAUGHT_ERROR_PAGE';
31
-
32
- Sentry.captureException(error_, {
33
- fingerprint: ['UNCAUGHT_ERROR_PAGE', error.digest]
34
- });
35
- });
36
- }, [error]);
37
-
38
10
  return (
39
11
  <section className="text-center px-6 my-14 md:px-0 md:m-14">
40
12
  <div className="text-7xl font-bold md:text-8xl">500</div>
@@ -1,10 +1,6 @@
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} */
@@ -18,7 +14,6 @@ module.exports = {
18
14
  { translationKey: 'size', key: 'size' }
19
15
  ],
20
16
  localization: {
21
- // If there is one locale in the locales array, the default locale will be hidden in the URL.
22
17
  locales: [
23
18
  {
24
19
  label: 'EN',
@@ -46,7 +41,7 @@ module.exports = {
46
41
  }
47
42
  ],
48
43
  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.
44
+ localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
50
45
  redirectToDefaultLocale: true,
51
46
  defaultCurrencyCode: 'usd'
52
47
  },
@@ -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
  });
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { ReactNode, useMemo, useRef, useCallback } from 'react';
4
- import { useGetMiniBasketQuery } from '@akinon/next/data/client/basket';
4
+ import { useGetBasketQuery } from '@akinon/next/data/client/basket';
5
5
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
6
6
  import {
7
7
  closeMiniBasket,
@@ -29,11 +29,8 @@ interface MenuItem {
29
29
  export default function ActionMenu() {
30
30
  const dispatch = useAppDispatch();
31
31
 
32
- const { data: miniBasket } = useGetMiniBasketQuery();
33
- const totalQuantity = useMemo(
34
- () => miniBasket?.total_quantity ?? 0,
35
- [miniBasket]
36
- );
32
+ const { data } = useGetBasketQuery();
33
+ const totalQuantity = useMemo(() => data?.total_quantity ?? 0, [data]);
37
34
 
38
35
  const { open: miniBasketOpen } = useAppSelector(
39
36
  (state) => state.root.miniBasket
@@ -5,7 +5,6 @@ import clsx from 'clsx';
5
5
  import {
6
6
  basketApi,
7
7
  useGetBasketQuery,
8
- useGetMiniBasketQuery,
9
8
  useUpdateQuantityMutation
10
9
  } from '@akinon/next/data/client/basket';
11
10
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
@@ -152,16 +151,12 @@ export default function MiniBasket() {
152
151
  );
153
152
  const dispatch = useAppDispatch();
154
153
  const { data: basket, isLoading, isSuccess } = useGetBasketQuery();
155
- const { data: miniBasket } = useGetMiniBasketQuery();
156
154
  const { t } = useLocalization();
157
155
  const { highlightedItem } = useAppSelector((state) => state.root.miniBasket);
158
156
  const [highlightedItemPk, setHighlightedItemPk] = useState(0);
159
157
  const [sortedBasket, setSortedBasket] = useState([]);
160
158
 
161
- const totalQuantity = useMemo(
162
- () => miniBasket?.total_quantity ?? 0,
163
- [miniBasket]
164
- );
159
+ const totalQuantity = useMemo(() => basket?.total_quantity ?? 0, [basket]);
165
160
  const miniBasketList = useRef();
166
161
 
167
162
  useEffect(() => {
@@ -10,10 +10,9 @@ import { yupResolver } from '@hookform/resolvers/yup';
10
10
  import clsx from 'clsx';
11
11
  import { useLocalization } from '@akinon/next/hooks';
12
12
  import { useOtpLoginMutation } from '@akinon/next/data/client/user';
13
- import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
13
+ import { useAppSelector } from '@akinon/next/redux/hooks';
14
14
  import PluginModule, { Component } from '@akinon/next/components/plugin-module';
15
15
  import { AuthError } from '@akinon/next/types';
16
- import { showPopup } from '@akinon/pz-otp/src/redux/reducer';
17
16
 
18
17
  const loginFormSchema = (t) =>
19
18
  yup.object().shape({
@@ -26,9 +25,9 @@ const loginFormSchema = (t) =>
26
25
  });
27
26
 
28
27
  export const OtpLogin = () => {
29
- const dispatch = useAppDispatch();
30
28
  const { user_phone_format } = useAppSelector((state) => state.config);
31
29
  const { t, locale } = useLocalization();
30
+ const [showOtpModal, setShowOtpModal] = useState(false);
32
31
  const [otpLoginMutation] = useOtpLoginMutation();
33
32
 
34
33
  const {
@@ -80,7 +79,7 @@ export const OtpLogin = () => {
80
79
  })
81
80
  .unwrap()
82
81
  .then(() => {
83
- dispatch(showPopup());
82
+ setShowOtpModal(true);
84
83
  })
85
84
  .catch((error) => {
86
85
  if (error.status === 429) {
@@ -137,14 +136,17 @@ export const OtpLogin = () => {
137
136
  </Button>
138
137
  </form>
139
138
 
140
- <PluginModule
141
- component={Component.Otp}
142
- props={{
143
- data: getValues(),
144
- submitAction: loginHandler,
145
- error: formError
146
- }}
147
- />
139
+ {showOtpModal && (
140
+ <PluginModule
141
+ component={Component.Otp}
142
+ props={{
143
+ setShowPopup: setShowOtpModal,
144
+ data: getValues(),
145
+ submitAction: loginHandler,
146
+ error: formError
147
+ }}
148
+ />
149
+ )}
148
150
  </section>
149
151
  );
150
152
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akinon/projectzero",
3
- "version": "1.82.0-rc.9",
3
+ "version": "1.83.0",
4
4
  "private": false,
5
5
  "description": "CLI tool to manage your Project Zero Next project",
6
6
  "bin": {
@@ -1,12 +0,0 @@
1
- import 'server-only';
2
- import { DynamicWidgetContainer } from '../dynamic-widget-renderer';
3
-
4
- export default async function WidgetPlaceholder({ slug }: { slug: string }) {
5
- return (
6
- <>
7
- <DynamicWidgetContainer />
8
- </>
9
- );
10
-
11
- return <div>WidgetPlaceholder</div>;
12
- }
@@ -1,106 +0,0 @@
1
- 'use client';
2
-
3
- import { useLocalization } from '@akinon/next/hooks';
4
- import { Basket } from '@akinon/next/types';
5
- import { Button, LoaderSpinner, Link } from '@theme/components';
6
- import { BasketItem, Summary } from '@theme/views/basket';
7
- import { ROUTES } from '@theme/routes';
8
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
9
- import { useEffect, useState } from 'react';
10
- import { pushCartView } from '@theme/utils/gtm';
11
-
12
- interface BasketContentProps {
13
- initialBasket: Basket;
14
- multiBasket: boolean;
15
- }
16
-
17
- export function BasketContent({
18
- initialBasket,
19
- multiBasket
20
- }: BasketContentProps) {
21
- const { t } = useLocalization();
22
- const [basket, setBasket] = useState<Basket>(initialBasket);
23
-
24
- useEffect(() => {
25
- if (basket) {
26
- const products = basket.basketitem_set.map((basketItem) => ({
27
- ...basketItem.product
28
- }));
29
- pushCartView(products);
30
- }
31
- }, [basket]);
32
-
33
- const handleBasketUpdate = (updatedBasket: Basket) => {
34
- setBasket(updatedBasket);
35
- };
36
-
37
- if (!basket) {
38
- return (
39
- <div className="flex justify-center w-full">
40
- <LoaderSpinner />
41
- </div>
42
- );
43
- }
44
-
45
- return (
46
- <div className="max-w-screen-xl p-4 flex flex-col text-primary-800 lg:p-8 xl:flex-row xl:mx-auto">
47
- {basket.basketitem_set && basket.basketitem_set.length > 0 ? (
48
- <>
49
- <div className="flex-1 xl:mr-16">
50
- <div className="flex items-center justify-between py-2 border-b border-gray-200 lg:py-3">
51
- <h2 className="text-xl lg:text-2xl font-light">
52
- {t('basket.my_cart')}
53
- </h2>
54
- <Link
55
- href={ROUTES.HOME}
56
- className="text-xs hover:text-secondary-500"
57
- >
58
- {t('basket.back_to_shopping')}
59
- </Link>
60
- </div>
61
- <ul>
62
- {multiBasket ? (
63
- <PluginModule
64
- component={Component.MultiBasket}
65
- props={{
66
- BasketItem,
67
- onBasketUpdate: handleBasketUpdate
68
- }}
69
- />
70
- ) : (
71
- basket.basketitem_set.map((basketItem, index) => (
72
- <BasketItem
73
- key={index}
74
- basketItem={basketItem}
75
- onBasketUpdate={handleBasketUpdate}
76
- />
77
- ))
78
- )}
79
- </ul>
80
- </div>
81
- <Summary basket={basket} onBasketUpdate={handleBasketUpdate} />
82
- </>
83
- ) : (
84
- <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">
85
- <h1
86
- className="w-full text-xl font-light text-secondary text-center sm:text-2xl"
87
- data-testid="basket-empty"
88
- >
89
- {t('basket.empty.title')}
90
- </h1>
91
-
92
- <div className="w-full text-sm text-black-800 text-center my-4 mb-2 sm:text-base">
93
- <p>{t('basket.empty.content_first')}</p>
94
- <p>{t('basket.empty.content_second')}.</p>
95
- </div>
96
-
97
- <Link href={ROUTES.HOME} passHref>
98
- <Button className="px-10 mt-2" appearance="filled">
99
- {t('basket.empty.button')}
100
- </Button>
101
- </Link>
102
- </div>
103
- )}
104
- </div>
105
- );
106
- }