@akinon/projectzero 1.84.0 → 1.85.0-rc.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 (30) hide show
  1. package/CHANGELOG.md +70 -3
  2. package/app-template/.gitignore +2 -0
  3. package/app-template/CHANGELOG.md +3612 -209
  4. package/app-template/next.config.mjs +4 -1
  5. package/app-template/package.json +18 -19
  6. package/app-template/public/locales/en/common.json +6 -0
  7. package/app-template/public/locales/tr/common.json +6 -0
  8. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +9 -82
  9. package/app-template/src/app/[commerce]/[locale]/[currency]/error.tsx +12 -15
  10. package/app-template/src/settings.js +6 -1
  11. package/app-template/src/views/basket/basket-content.tsx +106 -0
  12. package/app-template/src/views/basket/basket-item.tsx +16 -13
  13. package/app-template/src/views/basket/summary.tsx +10 -7
  14. package/app-template/src/views/header/action-menu.tsx +6 -3
  15. package/app-template/src/views/header/mini-basket.tsx +6 -1
  16. package/app-template/src/views/otp-login/index.tsx +12 -14
  17. package/codemods/sentry-9/index.js +30 -0
  18. package/codemods/sentry-9/remove-sentry-configs.js +14 -0
  19. package/codemods/sentry-9/remove-sentry-dependency.js +25 -0
  20. package/codemods/sentry-9/replace-error-page.js +32 -0
  21. package/commands/codemod.ts +18 -0
  22. package/commands/index.ts +3 -1
  23. package/dist/codemods/sentry-9/templates/error.js +14 -0
  24. package/dist/commands/codemod.js +16 -0
  25. package/dist/commands/index.js +3 -1
  26. package/package.json +1 -1
  27. package/app-template/sentry.client.config.ts +0 -16
  28. package/app-template/sentry.edge.config.ts +0 -3
  29. package/app-template/sentry.properties +0 -4
  30. package/app-template/sentry.server.config.ts +0 -3
@@ -26,7 +26,10 @@ const withPwaConfig = withPWA({
26
26
 
27
27
  const sentryConfig = {
28
28
  silent: true,
29
- dryRun: !process.env.SENTRY_DSN
29
+ dryRun: !process.env.SENTRY_DSN,
30
+ org: 'akinon'
31
+ // project: 'enter_your_project_name_here',
32
+ // authToken: 'enter_your_auth_token_here'
30
33
  };
31
34
 
32
35
  const enhancedConfig = withPzConfig(nextConfig);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "projectzeronext",
3
- "version": "1.84.0",
3
+ "version": "1.85.0-rc.0",
4
4
  "private": true,
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -22,26 +22,25 @@
22
22
  "prestart": "pz-prestart"
23
23
  },
24
24
  "dependencies": {
25
- "@akinon/next": "1.84.0",
26
- "@akinon/pz-akifast": "1.84.0",
27
- "@akinon/pz-b2b": "1.84.0",
28
- "@akinon/pz-basket-gift-pack": "1.84.0",
29
- "@akinon/pz-bkm": "1.84.0",
30
- "@akinon/pz-checkout-gift-pack": "1.84.0",
31
- "@akinon/pz-click-collect": "1.84.0",
32
- "@akinon/pz-credit-payment": "1.84.0",
33
- "@akinon/pz-gpay": "1.84.0",
34
- "@akinon/pz-masterpass": "1.84.0",
35
- "@akinon/pz-one-click-checkout": "1.84.0",
36
- "@akinon/pz-otp": "1.84.0",
37
- "@akinon/pz-pay-on-delivery": "1.84.0",
38
- "@akinon/pz-saved-card": "1.84.0",
39
- "@akinon/pz-tabby-extension": "1.84.0",
40
- "@akinon/pz-tamara-extension": "1.84.0",
25
+ "@akinon/next": "1.85.0-rc.0",
26
+ "@akinon/pz-akifast": "1.85.0-rc.0",
27
+ "@akinon/pz-b2b": "1.85.0-rc.0",
28
+ "@akinon/pz-basket-gift-pack": "1.85.0-rc.0",
29
+ "@akinon/pz-bkm": "1.85.0-rc.0",
30
+ "@akinon/pz-checkout-gift-pack": "1.85.0-rc.0",
31
+ "@akinon/pz-click-collect": "1.85.0-rc.0",
32
+ "@akinon/pz-credit-payment": "1.85.0-rc.0",
33
+ "@akinon/pz-gpay": "1.85.0-rc.0",
34
+ "@akinon/pz-masterpass": "1.85.0-rc.0",
35
+ "@akinon/pz-one-click-checkout": "1.85.0-rc.0",
36
+ "@akinon/pz-otp": "1.85.0-rc.0",
37
+ "@akinon/pz-pay-on-delivery": "1.85.0-rc.0",
38
+ "@akinon/pz-saved-card": "1.85.0-rc.0",
39
+ "@akinon/pz-tabby-extension": "1.85.0-rc.0",
40
+ "@akinon/pz-tamara-extension": "1.85.0-rc.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": "7.116.0",
45
44
  "dayjs": "1.11.5",
46
45
  "lossless-json": "2.0.5",
47
46
  "next": "14.2.25",
@@ -62,7 +61,7 @@
62
61
  "yup": "0.32.11"
63
62
  },
64
63
  "devDependencies": {
65
- "@akinon/eslint-plugin-projectzero": "1.84.0",
64
+ "@akinon/eslint-plugin-projectzero": "1.85.0-rc.0",
66
65
  "@semantic-release/changelog": "6.0.2",
67
66
  "@semantic-release/exec": "6.0.3",
68
67
  "@semantic-release/git": "10.0.1",
@@ -38,6 +38,12 @@
38
38
  "description": "Please try again later.",
39
39
  "link_text": "Return to home page"
40
40
  },
41
+ "client_error": {
42
+ "title": "We encountered a problem with the page.",
43
+ "description": "This appears to be a client-side issue. Please try refreshing the page or clearing your browser cache.",
44
+ "link_text": "Return to home page"
45
+ },
46
+ "try_again": "Try Again",
41
47
  "breadcrumb": {
42
48
  "homepage": "Homepage"
43
49
  },
@@ -38,6 +38,12 @@
38
38
  "description": "Lütfen daha sonra tekrar deneyiniz.",
39
39
  "link_text": "Ana sayfaya dön"
40
40
  },
41
+ "client_error": {
42
+ "title": "Sayfada bir sorunla karşılaştık.",
43
+ "description": "Bu bir tarayıcı hatası gibi görünüyor. Lütfen sayfayı yenileyin veya tarayıcı önbelleğinizi temizleyin.",
44
+ "link_text": "Ana sayfaya dön"
45
+ },
46
+ "try_again": "Tekrar Dene",
41
47
  "breadcrumb": {
42
48
  "homepage": "Anasayfa"
43
49
  },
@@ -1,87 +1,14 @@
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';
1
+ import { BasketContent } from '@theme/views/basket/basket-content';
2
+ import { getBasketData } from '@akinon/next/data/server/basket';
11
3
  import settings from '@theme/settings';
12
4
 
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>
5
+ export default async function Page() {
6
+ const { basket } = await getBasketData();
72
7
 
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>
8
+ const multiBasket: boolean =
9
+ typeof settings.plugins?.multiBasket === 'boolean'
10
+ ? settings.plugins.multiBasket
11
+ : false;
77
12
 
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
- );
13
+ return <BasketContent initialBasket={basket} multiBasket={multiBasket} />;
87
14
  }
@@ -1,20 +1,17 @@
1
1
  'use client';
2
2
 
3
- import { useLocalization } from '@akinon/next/hooks';
4
- import { Link } from '@theme/components';
5
- import { ROUTES } from '@theme/routes';
3
+ import { useSentryUncaughtErrors } from '@akinon/next/hooks';
4
+ import PzErrorPage from '@akinon/next/views/error-page';
6
5
 
7
- export default function Error() {
8
- const { t } = useLocalization();
6
+ export default function ErrorPage({
7
+ error,
8
+ reset
9
+ }: {
10
+ error: Error & { digest?: string; isServerError?: boolean };
11
+ reset: () => void;
12
+ }) {
13
+ // DO NOT REMOVE THIS LINE TO REPORT UNCAUGHT ERRORS TO SENTRY
14
+ useSentryUncaughtErrors(error);
9
15
 
10
- return (
11
- <section className="text-center px-6 my-14 md:px-0 md:m-14">
12
- <div className="text-7xl font-bold md:text-8xl">500</div>
13
- <h1 className="text-lg md:text-xl"> {t('common.page_500.title')} </h1>
14
- <p className="text-lg md:text-xl"> {t('common.page_500.description')} </p>
15
- <Link href={ROUTES.HOME} className="text-lg underline">
16
- {t('common.page_500.link_text')}
17
- </Link>
18
- </section>
19
- );
16
+ return <PzErrorPage error={error} reset={reset} />;
20
17
  }
@@ -1,6 +1,10 @@
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
+
4
8
  const commerceUrl = encodeURI(process.env.SERVICE_BACKEND_URL ?? 'default');
5
9
 
6
10
  /** @type {import('@akinon/next/types').Settings} */
@@ -14,6 +18,7 @@ module.exports = {
14
18
  { translationKey: 'size', key: 'size' }
15
19
  ],
16
20
  localization: {
21
+ // If there is one locale in the locales array, the default locale will be hidden in the URL.
17
22
  locales: [
18
23
  {
19
24
  label: 'EN',
@@ -41,7 +46,7 @@ module.exports = {
41
46
  }
42
47
  ],
43
48
  defaultLocaleValue: 'en',
44
- localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
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.
45
50
  redirectToDefaultLocale: true,
46
51
  defaultCurrencyCode: 'usd'
47
52
  },
@@ -0,0 +1,106 @@
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
+ }
@@ -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 { BasketItem as BasketItemType } from '@akinon/next/types';
6
+ import { Basket, 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,11 +19,12 @@ import { pushRemoveFromCart } from '@theme/utils/gtm';
19
19
  interface Props {
20
20
  basketItem?: BasketItemType;
21
21
  namespace?: string;
22
+ onBasketUpdate?: (basket: Basket) => void;
22
23
  }
23
24
 
24
25
  export const BasketItem = (props: Props) => {
25
26
  const { t } = useLocalization();
26
- const { basketItem, namespace } = props;
27
+ const { basketItem, namespace, onBasketUpdate } = props;
27
28
  const [updateQuantityMutation] = useUpdateQuantityMutation();
28
29
  const dispatch = useAppDispatch();
29
30
  const [isRemoveBasketModalOpen, setRemoveBasketModalOpen] = useState(false);
@@ -49,19 +50,21 @@ export const BasketItem = (props: Props) => {
49
50
  requestParams.namespace = namespace;
50
51
  }
51
52
 
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
- )
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
+ }
63
62
  )
64
63
  );
64
+ onBasketUpdate?.(response.basket);
65
+ } catch (error) {
66
+ console.error('Error updating quantity:', error);
67
+ }
65
68
  };
66
69
 
67
70
  const deleteProduct = async (productPk?: number) => {
@@ -18,6 +18,7 @@ import clsx from 'clsx';
18
18
 
19
19
  interface Props {
20
20
  basket: Basket;
21
+ onBasketUpdate?: (basket: Basket) => void;
21
22
  }
22
23
 
23
24
  const voucherCodeFormSchema = (t) =>
@@ -27,7 +28,7 @@ const voucherCodeFormSchema = (t) =>
27
28
 
28
29
  export const Summary = (props: Props) => {
29
30
  const { t } = useLocalization();
30
- const { basket } = props;
31
+ const { basket, onBasketUpdate } = props;
31
32
  const router = useRouter();
32
33
  const {
33
34
  register,
@@ -53,7 +54,7 @@ export const Summary = (props: Props) => {
53
54
  const removeVoucherCode = () => {
54
55
  removeVoucherCodeMutation()
55
56
  .unwrap()
56
- .then((basket) =>
57
+ .then((basket) => {
57
58
  dispatch(
58
59
  basketApi.util.updateQueryData(
59
60
  'getBasket',
@@ -62,8 +63,9 @@ export const Summary = (props: Props) => {
62
63
  Object.assign(draftBasket, basket);
63
64
  }
64
65
  )
65
- )
66
- )
66
+ );
67
+ onBasketUpdate?.(basket);
68
+ })
67
69
  .catch((error: Error) => {
68
70
  setError('voucherCode', { message: error.data.non_field_errors });
69
71
  });
@@ -74,7 +76,7 @@ export const Summary = (props: Props) => {
74
76
  voucher_code: data.voucherCode
75
77
  })
76
78
  .unwrap()
77
- .then((basket) =>
79
+ .then((basket) => {
78
80
  dispatch(
79
81
  basketApi.util.updateQueryData(
80
82
  'getBasket',
@@ -83,8 +85,9 @@ export const Summary = (props: Props) => {
83
85
  Object.assign(draftBasket, basket);
84
86
  }
85
87
  )
86
- )
87
- )
88
+ );
89
+ onBasketUpdate?.(basket);
90
+ })
88
91
  .catch((error: Error) => {
89
92
  setError('voucherCode', { message: error.data.non_field_errors });
90
93
  });
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
 
3
3
  import { ReactNode, useMemo, useRef, useCallback } from 'react';
4
- import { useGetBasketQuery } from '@akinon/next/data/client/basket';
4
+ import { useGetMiniBasketQuery } from '@akinon/next/data/client/basket';
5
5
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
6
6
  import {
7
7
  closeMiniBasket,
@@ -29,8 +29,11 @@ interface MenuItem {
29
29
  export default function ActionMenu() {
30
30
  const dispatch = useAppDispatch();
31
31
 
32
- const { data } = useGetBasketQuery();
33
- const totalQuantity = useMemo(() => data?.total_quantity ?? 0, [data]);
32
+ const { data: miniBasket } = useGetMiniBasketQuery();
33
+ const totalQuantity = useMemo(
34
+ () => miniBasket?.total_quantity ?? 0,
35
+ [miniBasket]
36
+ );
34
37
 
35
38
  const { open: miniBasketOpen } = useAppSelector(
36
39
  (state) => state.root.miniBasket
@@ -5,6 +5,7 @@ import clsx from 'clsx';
5
5
  import {
6
6
  basketApi,
7
7
  useGetBasketQuery,
8
+ useGetMiniBasketQuery,
8
9
  useUpdateQuantityMutation
9
10
  } from '@akinon/next/data/client/basket';
10
11
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
@@ -151,12 +152,16 @@ export default function MiniBasket() {
151
152
  );
152
153
  const dispatch = useAppDispatch();
153
154
  const { data: basket, isLoading, isSuccess } = useGetBasketQuery();
155
+ const { data: miniBasket } = useGetMiniBasketQuery();
154
156
  const { t } = useLocalization();
155
157
  const { highlightedItem } = useAppSelector((state) => state.root.miniBasket);
156
158
  const [highlightedItemPk, setHighlightedItemPk] = useState(0);
157
159
  const [sortedBasket, setSortedBasket] = useState([]);
158
160
 
159
- const totalQuantity = useMemo(() => basket?.total_quantity ?? 0, [basket]);
161
+ const totalQuantity = useMemo(
162
+ () => miniBasket?.total_quantity ?? 0,
163
+ [miniBasket]
164
+ );
160
165
  const miniBasketList = useRef();
161
166
 
162
167
  useEffect(() => {
@@ -10,9 +10,10 @@ 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 { useAppSelector } from '@akinon/next/redux/hooks';
13
+ import { useAppDispatch, 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';
16
17
 
17
18
  const loginFormSchema = (t) =>
18
19
  yup.object().shape({
@@ -25,9 +26,9 @@ const loginFormSchema = (t) =>
25
26
  });
26
27
 
27
28
  export const OtpLogin = () => {
29
+ const dispatch = useAppDispatch();
28
30
  const { user_phone_format } = useAppSelector((state) => state.config);
29
31
  const { t, locale } = useLocalization();
30
- const [showOtpModal, setShowOtpModal] = useState(false);
31
32
  const [otpLoginMutation] = useOtpLoginMutation();
32
33
 
33
34
  const {
@@ -79,7 +80,7 @@ export const OtpLogin = () => {
79
80
  })
80
81
  .unwrap()
81
82
  .then(() => {
82
- setShowOtpModal(true);
83
+ dispatch(showPopup());
83
84
  })
84
85
  .catch((error) => {
85
86
  if (error.status === 429) {
@@ -136,17 +137,14 @@ export const OtpLogin = () => {
136
137
  </Button>
137
138
  </form>
138
139
 
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
- )}
140
+ <PluginModule
141
+ component={Component.Otp}
142
+ props={{
143
+ data: getValues(),
144
+ submitAction: loginHandler,
145
+ error: formError
146
+ }}
147
+ />
150
148
  </section>
151
149
  );
152
150
  };
@@ -0,0 +1,30 @@
1
+ const path = require('path');
2
+ const { execSync } = require('child_process');
3
+
4
+ const codemodScripts = [
5
+ path.resolve(__dirname, 'remove-sentry-dependency.js'),
6
+ path.resolve(__dirname, 'remove-sentry-configs.js'),
7
+ path.resolve(__dirname, 'replace-error-page.js')
8
+ ];
9
+
10
+ const transform = () => {
11
+ const workingDir = path.resolve(process.cwd());
12
+
13
+ codemodScripts.forEach((script) => {
14
+ try {
15
+ execSync(
16
+ `jscodeshift --ignore-pattern="**/node_modules/**" -t ${script} ${workingDir} --extensions=json,ts,tsx,js,jsx,properties,md`,
17
+ {
18
+ cwd: workingDir,
19
+ stdio: 'inherit'
20
+ }
21
+ );
22
+ } catch (e) {
23
+ console.error(e);
24
+ }
25
+ });
26
+ };
27
+
28
+ module.exports = {
29
+ transform
30
+ };
@@ -0,0 +1,14 @@
1
+ const fs = require('fs');
2
+
3
+ const transform = (fileInfo, api, options) => {
4
+ const filePath = fileInfo.path;
5
+ const regex = /sentry\.\w+\.config\.(ts|js)$|sentry\.properties$/i;
6
+
7
+ if (regex.test(filePath) && fs.existsSync(filePath)) {
8
+ fs.unlinkSync(filePath);
9
+ }
10
+
11
+ return fileInfo.source;
12
+ };
13
+
14
+ module.exports = transform;
@@ -0,0 +1,25 @@
1
+ const transform = (fileInfo, api, options) => {
2
+ if (fileInfo.path.endsWith('package.json')) {
3
+ const packageJson = JSON.parse(fileInfo.source);
4
+
5
+ if (
6
+ packageJson.dependencies &&
7
+ packageJson.dependencies['@sentry/nextjs']
8
+ ) {
9
+ delete packageJson.dependencies['@sentry/nextjs'];
10
+ }
11
+
12
+ if (
13
+ packageJson.devDependencies &&
14
+ packageJson.devDependencies['@sentry/nextjs']
15
+ ) {
16
+ delete packageJson.devDependencies['@sentry/nextjs'];
17
+ }
18
+
19
+ return JSON.stringify(packageJson, null, 2);
20
+ }
21
+
22
+ return fileInfo.source;
23
+ };
24
+
25
+ module.exports = transform;