@akinon/projectzero 1.99.0-rc.70 → 1.99.0-snapshot-ZERO-3640-20250919140314

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 (64) hide show
  1. package/CHANGELOG.md +5 -240
  2. package/app-template/.env.example +0 -1
  3. package/app-template/CHANGELOG.md +300 -5065
  4. package/app-template/README.md +1 -25
  5. package/app-template/package.json +19 -21
  6. package/app-template/public/locales/en/common.json +1 -48
  7. package/app-template/public/locales/tr/common.json +1 -48
  8. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
  9. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +4 -17
  10. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +1 -12
  11. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +11 -29
  12. package/app-template/src/app/[commerce]/[locale]/[currency]/landing-page/[pk]/page.tsx +1 -12
  13. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +10 -28
  14. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +1 -12
  15. package/app-template/src/app/api/form/[...id]/route.ts +7 -1
  16. package/app-template/src/assets/fonts/pz-icon.css +0 -3
  17. package/app-template/src/components/__tests__/link.test.tsx +0 -2
  18. package/app-template/src/components/accordion.tsx +19 -22
  19. package/app-template/src/components/currency-select.tsx +0 -1
  20. package/app-template/src/components/file-input.tsx +7 -27
  21. package/app-template/src/components/generate-form-fields.tsx +4 -43
  22. package/app-template/src/components/input.tsx +2 -9
  23. package/app-template/src/components/modal.tsx +16 -32
  24. package/app-template/src/components/pagination.tsx +0 -1
  25. package/app-template/src/components/select.tsx +26 -38
  26. package/app-template/src/components/types/index.ts +1 -25
  27. package/app-template/src/hooks/index.ts +0 -2
  28. package/app-template/src/plugins.js +1 -3
  29. package/app-template/src/settings.js +2 -8
  30. package/app-template/src/types/index.ts +3 -74
  31. package/app-template/src/views/account/address-form.tsx +4 -8
  32. package/app-template/src/views/account/contact-form.tsx +1 -1
  33. package/app-template/src/views/account/content-header.tsx +2 -2
  34. package/app-template/src/views/account/faq/faq-tabs.tsx +2 -8
  35. package/app-template/src/views/basket/basket-item.tsx +14 -22
  36. package/app-template/src/views/basket/summary.tsx +7 -10
  37. package/app-template/src/views/breadcrumb.tsx +2 -2
  38. package/app-template/src/views/category/category-info.tsx +0 -1
  39. package/app-template/src/views/category/filters/index.tsx +1 -1
  40. package/app-template/src/views/guest-login/index.tsx +1 -6
  41. package/app-template/src/views/header/action-menu.tsx +1 -1
  42. package/app-template/src/views/header/search/index.tsx +5 -17
  43. package/app-template/src/views/login/index.tsx +10 -11
  44. package/app-template/src/views/otp-login/index.tsx +6 -11
  45. package/app-template/src/views/product/product-info.tsx +263 -62
  46. package/app-template/src/views/product/slider.tsx +73 -86
  47. package/app-template/src/views/register/index.tsx +11 -15
  48. package/app-template/src/widgets/footer-menu.tsx +2 -6
  49. package/commands/plugins.ts +16 -63
  50. package/dist/commands/plugins.js +16 -57
  51. package/package.json +1 -1
  52. package/app-template/.github/instructions/account.instructions.md +0 -749
  53. package/app-template/.github/instructions/edge-cases.instructions.md +0 -73
  54. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
  55. package/app-template/src/app/api/image-proxy/route.ts +0 -1
  56. package/app-template/src/app/api/similar-product-list/route.ts +0 -1
  57. package/app-template/src/app/api/similar-products/route.ts +0 -1
  58. package/app-template/src/hooks/use-product-cart.ts +0 -77
  59. package/app-template/src/hooks/use-stock-alert.ts +0 -74
  60. package/app-template/src/utils/variant-validation.ts +0 -41
  61. package/app-template/src/views/basket/basket-content.tsx +0 -106
  62. package/app-template/src/views/product/product-actions.tsx +0 -165
  63. package/app-template/src/views/product/product-share.tsx +0 -56
  64. package/app-template/src/views/product/product-variants.tsx +0 -26
@@ -1,73 +1,177 @@
1
1
  'use client';
2
2
 
3
3
  import clsx from 'clsx';
4
+ import { Button, Icon, Modal } from '@theme/components';
5
+ import { useAddProductToBasket } from '../../hooks';
4
6
  import React, { useEffect, useState } from 'react';
5
- import { PriceWrapper } from '@theme/views/product';
7
+ import { useAddStockAlertMutation } from '@akinon/next/data/client/wishlist';
8
+ import { pushAddToCart, pushProductViewed } from '@theme/utils/gtm';
9
+ import { PriceWrapper, Variant } from '@theme/views/product';
10
+ import Share from '@theme/views/share';
6
11
  import { ProductPageProps } from './layout';
7
12
  import MiscButtons from './misc-buttons';
8
- import { pushProductViewed } from '@theme/utils/gtm';
13
+ import { useLocalization } from '@akinon/next/hooks';
14
+ import PluginModule, { Component } from '@akinon/next/components/plugin-module';
15
+ import { Trans } from '@akinon/next/components/trans';
9
16
  import { useSession } from 'next-auth/react';
10
- import { isVariantSelectionComplete } from '../../utils/variant-validation';
11
- import { useProductCart } from '../../hooks/use-product-cart';
12
- import { useStockAlert } from '../../hooks/use-stock-alert';
13
- import { ProductVariants } from './product-variants';
14
- import { ProductActions } from './product-actions';
15
- import { ProductShare } from './product-share';
16
17
 
17
18
  export default function ProductInfo({ data }: ProductPageProps) {
19
+ const { t } = useLocalization();
18
20
  const { data: session } = useSession();
21
+ const [currentUrl, setCurrentUrl] = useState(null);
22
+ const [productError, setProductError] = useState(null);
23
+ const [isModalOpen, setIsModalOpen] = useState(false);
24
+ const [stockAlertResponseMessage, setStockAlertResponseMessage] =
25
+ useState(null);
19
26
  const [isVariantLoading, setIsVariantLoading] = useState(false);
20
27
 
28
+ const [addProduct, { isLoading: isAddToCartLoading }] =
29
+ useAddProductToBasket();
30
+ const [addStockAlert, { isLoading: isAddToStockAlertLoading }] =
31
+ useAddStockAlertMutation();
21
32
  const inStock = data.selected_variant !== null || data.product.in_stock;
22
33
 
23
- const {
24
- addProductToCart,
25
- productError: cartError,
26
- clearProductError: clearCartError,
27
- isAddToCartLoading
28
- } = useProductCart({
29
- product: data.product,
30
- variants: data.variants
31
- });
32
-
33
- const {
34
- addProductToStockAlertList,
35
- isModalOpen,
36
- stockAlertResponseMessage,
37
- productError: stockError,
38
- isAddToStockAlertLoading,
39
- closeModal,
40
- clearError: clearStockError
41
- } = useStockAlert({
42
- productPk: data.product.pk,
43
- userEmail: session?.user?.email
44
- });
45
-
46
- const productError = cartError || stockError;
47
- const clearProductError = () => {
48
- clearCartError();
49
- clearStockError();
50
- };
51
-
52
34
  useEffect(() => {
53
- isVariantSelectionComplete(data.variants) && setIsVariantLoading(false);
35
+ isVariantSelectionComplete() && setIsVariantLoading(false);
36
+
54
37
  !inStock && setIsVariantLoading(false);
55
- }, [data, inStock]);
38
+ }, [data]); // eslint-disable-line react-hooks/exhaustive-deps
56
39
 
57
40
  useEffect(() => {
58
41
  if (isVariantLoading) {
59
- clearProductError();
42
+ setProductError(null);
60
43
  }
61
- // eslint-disable-next-line react-hooks/exhaustive-deps
62
44
  }, [isVariantLoading]);
63
45
 
46
+ useEffect(() => {
47
+ setCurrentUrl(window.location.href);
48
+ }, [currentUrl]);
49
+
64
50
  useEffect(() => {
65
51
  pushProductViewed(data?.product);
66
52
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
67
53
 
68
- const handleVariantChange = () => {
69
- clearProductError();
70
- setIsVariantLoading(true);
54
+ const addProductToCart = async () => {
55
+ if (!variantsSelectionCheck()) {
56
+ return;
57
+ }
58
+
59
+ try {
60
+ await addProduct({
61
+ product: data.product.pk,
62
+ quantity: 1,
63
+ attributes: {}
64
+ });
65
+
66
+ pushAddToCart(data?.product);
67
+ } catch (error) {
68
+ setProductError(
69
+ error?.data?.non_field_errors ||
70
+ Object.keys(error?.data).map(
71
+ (key) => `${key}: ${error?.data[key].join(', ')}`
72
+ )
73
+ );
74
+ }
75
+ };
76
+
77
+ const variantsSelectionCheck = () => {
78
+ const unselectedVariant = data.variants.find((variant) =>
79
+ variant.options.every((opt) => !opt.is_selected)
80
+ );
81
+
82
+ if (unselectedVariant) {
83
+ setProductError(() => (
84
+ <Trans
85
+ i18nKey="product.please_select_variant"
86
+ components={{
87
+ VariantName: <span>{unselectedVariant.attribute_name}</span>
88
+ }}
89
+ />
90
+ ));
91
+
92
+ return false;
93
+ }
94
+
95
+ return true;
96
+ };
97
+
98
+ const isVariantSelectionComplete = () => {
99
+ return data?.variants.every((variant) =>
100
+ variant?.options.some((opt) => opt.is_selected)
101
+ );
102
+ };
103
+
104
+ const addProductToStockAlertList = async () => {
105
+ try {
106
+ await addStockAlert({
107
+ productPk: data.product.pk,
108
+ email: session?.user?.email
109
+ })
110
+ .unwrap()
111
+ .then(handleSuccess)
112
+ .catch((err) => handleError(err));
113
+ } catch (error) {
114
+ setProductError(error?.data?.non_field_errors || null);
115
+ }
116
+ };
117
+
118
+ const handleModalClick = () => {
119
+ setIsModalOpen(false);
120
+ };
121
+
122
+ const handleSuccess = () => {
123
+ setStockAlertResponseMessage(() => (
124
+ <Trans
125
+ i18nKey="product.stock_alert.success_description"
126
+ components={{
127
+ Email: <span>{session?.user?.email}</span>
128
+ }}
129
+ />
130
+ ));
131
+ setIsModalOpen(true);
132
+ };
133
+
134
+ const handleError = (err) => {
135
+ if (err.status !== 401) {
136
+ setStockAlertResponseMessage(
137
+ t('product.stock_alert.error_description').toString()
138
+ );
139
+ setIsModalOpen(true);
140
+ }
141
+ };
142
+
143
+ const checkoutProviderProps = {
144
+ product: data.product,
145
+ clearBasket: true,
146
+ addBeforeClick: variantsSelectionCheck,
147
+ openMiniBasket: false,
148
+ className: clsx([
149
+ 'py-2.5',
150
+ 'bg-black',
151
+ 'relative',
152
+ 'hover:bg-black',
153
+ 'before:content-[""]',
154
+ 'before:w-6',
155
+ 'before:h-6',
156
+ 'before:bg-white',
157
+ 'before:absolute',
158
+ 'before:rounded-r-[18px]',
159
+ 'before:left-0',
160
+ 'after:content-[""]',
161
+ 'after:absolute',
162
+ 'after:w-3',
163
+ 'after:h-3',
164
+ 'after:bg-[#d02c2f]',
165
+ 'after:rounded-xl',
166
+ 'after:left-1'
167
+ ]),
168
+ onError: (error) =>
169
+ setProductError(
170
+ error?.data?.non_field_errors ||
171
+ Object.keys(error?.data).map(
172
+ (key) => `${key}: ${error?.data[key].join(', ')}`
173
+ )
174
+ )
71
175
  };
72
176
 
73
177
  return (
@@ -83,26 +187,72 @@ export default function ProductInfo({ data }: ProductPageProps) {
83
187
  retailPrice={data.product.retail_price}
84
188
  />
85
189
  </div>
190
+ <div className="flex flex-col">
191
+ {data.variants.map((variant) => (
192
+ <Variant
193
+ key={variant.attribute_key}
194
+ {...variant}
195
+ className="items-center mt-8"
196
+ onChange={() => {
197
+ setProductError(null);
198
+ setIsVariantLoading(true);
199
+ }}
200
+ />
201
+ ))}
202
+ </div>
86
203
 
87
- <ProductVariants
88
- variants={data.variants}
89
- onVariantChange={handleVariantChange}
204
+ {productError && (
205
+ <div className="mt-4 text-xs text-center text-error">
206
+ {productError}
207
+ </div>
208
+ )}
209
+
210
+ <Button
211
+ disabled={
212
+ isAddToCartLoading || isAddToStockAlertLoading || isVariantLoading
213
+ }
214
+ className={clsx(
215
+ 'fixed bottom-0 right-0 w-1/2 h-14 z-[20] flex items-center justify-center fill-primary-foreground',
216
+ 'hover:fill-primary sm:relative sm:w-full sm:mt-3 sm:font-semibold sm:h-12'
217
+ )}
218
+ onClick={() => {
219
+ setProductError(null);
220
+
221
+ if (inStock) {
222
+ addProductToCart();
223
+ } else {
224
+ addProductToStockAlertList();
225
+ }
226
+ }}
227
+ data-testid="product-add-to-cart"
228
+ >
229
+ {isVariantLoading ? (
230
+ <Icon
231
+ name="spinner"
232
+ size={20}
233
+ className="animate-spin mr-4 fill-primary"
234
+ />
235
+ ) : inStock ? (
236
+ <span>{t('product.add_to_cart')}</span>
237
+ ) : (
238
+ <>
239
+ <Icon name="bell" size={20} className="mr-4" />
240
+ <span>{t('product.add_stock_alert')}</span>
241
+ </>
242
+ )}
243
+ </Button>
244
+
245
+ <PluginModule
246
+ component={Component.AkifastCheckoutButton}
247
+ props={{
248
+ ...checkoutProviderProps,
249
+ isPdp: true
250
+ }}
90
251
  />
91
252
 
92
- <ProductActions
93
- product={data.product}
94
- variants={data.variants}
95
- inStock={inStock}
96
- isVariantLoading={isVariantLoading}
97
- onAddToCart={addProductToCart}
98
- onAddToStockAlert={addProductToStockAlertList}
99
- onClearError={clearProductError}
100
- isAddToCartLoading={isAddToCartLoading}
101
- isAddToStockAlertLoading={isAddToStockAlertLoading}
102
- productError={productError}
103
- isModalOpen={isModalOpen}
104
- stockAlertResponseMessage={stockAlertResponseMessage}
105
- onCloseModal={closeModal}
253
+ <PluginModule
254
+ component={Component.OneClickCheckoutButtons}
255
+ props={checkoutProviderProps}
106
256
  />
107
257
 
108
258
  <MiscButtons
@@ -111,7 +261,58 @@ export default function ProductInfo({ data }: ProductPageProps) {
111
261
  variants={data.variants}
112
262
  />
113
263
 
114
- <ProductShare productName={data.product.name} className="my-2 sm:mb-4" />
264
+ <Share
265
+ className="my-2 sm:mb-4"
266
+ buttonText={t('product.share')}
267
+ items={[
268
+ {
269
+ href: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(
270
+ currentUrl
271
+ )}`,
272
+ iconName: 'facebook',
273
+ iconSize: 22
274
+ },
275
+ {
276
+ href: `https://twitter.com/intent/tweet?text=${encodeURIComponent(
277
+ currentUrl
278
+ )}`,
279
+ iconName: 'twitter',
280
+ iconSize: 22
281
+ },
282
+ {
283
+ href: `https://api.whatsapp.com/send?text=${
284
+ data.product.name
285
+ }%20${encodeURIComponent(currentUrl)}`,
286
+ iconName: 'whatsapp',
287
+ iconSize: 22
288
+ }
289
+ ]}
290
+ />
291
+
292
+ <Modal
293
+ portalId="stock-alert-modal"
294
+ open={isModalOpen}
295
+ setOpen={setIsModalOpen}
296
+ showCloseButton={false}
297
+ className="w-5/6 md:max-w-md"
298
+ >
299
+ <div className="flex flex-col items-center justify-center gap-4 px-6 py-9">
300
+ <Icon name="bell" size={48} />
301
+ <h2 className="text-xl font-semibold">
302
+ {t('product.stock_alert.title')}
303
+ </h2>
304
+ <div className="max-w-40 text-xs text-center leading-4">
305
+ <p>{stockAlertResponseMessage}</p>
306
+ </div>
307
+ <Button
308
+ onClick={handleModalClick}
309
+ appearance="outlined"
310
+ className="font-semibold px-10 h-12"
311
+ >
312
+ {t('product.stock_alert.close_button')}
313
+ </Button>
314
+ </div>
315
+ </Modal>
115
316
  </>
116
317
  );
117
318
  }
@@ -7,7 +7,6 @@ import { Product } from '@akinon/next/types';
7
7
  import { Image } from '@akinon/next/components/image';
8
8
  import useFavButton from '../../hooks/use-fav-button';
9
9
  import { twMerge } from 'tailwind-merge';
10
- import PluginModule, { Component } from '@akinon/next/components/plugin-module';
11
10
 
12
11
  type ProductSliderItem = {
13
12
  product: Product;
@@ -36,102 +35,90 @@ export default function ProductInfoSlider({ product }: ProductSliderItem) {
36
35
  carouselRef.current?.next();
37
36
  };
38
37
 
39
- const handleThumbnailClick = (index: number) => {
38
+ const handleThumbnailClick = (index) => {
40
39
  setActiveIndex(index);
41
40
  carouselRef.current?.goToSlide(index);
42
41
  };
43
42
 
44
43
  return (
45
- <>
46
- <div className="lg:grid lg:grid-cols-6">
47
- <div className="lg:col-span-1">
48
- <div className="flex flex-col items-center justify-center md:mr-[6px]">
49
- <button
50
- onClick={goToPrev}
51
- className={twMerge(
52
- 'hidden justify-center p-2 mb-3 border border-gray-100 rounded-full cursor-pointer lg:block',
53
- [activeIndex === 0 && 'cursor-not-allowed opacity-45']
54
- )}
55
- disabled={activeIndex === 0}
56
- >
57
- <Icon name="chevron-up" size={15} className="fill-[#000000]" />
58
- </button>
59
- <div className="hidden flex-col items-center overflow-scroll w-[80px] max-h-[620px] lg:block">
60
- {product?.productimage_set?.map((item, index) => (
61
- <Image
62
- key={index}
63
- src={item.image}
64
- alt={`Thumbnail ${index}`}
65
- width={80}
66
- height={128}
67
- aspectRatio={80 / 128}
68
- className={twMerge('cursor-pointer', [
69
- activeIndex === index && 'border-2 border-primary'
70
- ])}
71
- onClick={() => handleThumbnailClick(index)}
72
- />
73
- ))}
74
- </div>
75
- <button
76
- onClick={goToNext}
77
- className={twMerge(
78
- 'hidden justify-center p-2 mt-3 border border-gray-100 rounded-full cursor-pointer lg:block',
79
- [
80
- activeIndex === product.productimage_set.length - 1 &&
81
- 'cursor-not-allowed opacity-45'
82
- ]
83
- )}
84
- disabled={activeIndex === product.productimage_set.length - 1}
85
- >
86
- <Icon name="chevron-down" size={15} className="fill-[#000000]" />
87
- </button>
88
- </div>
89
- </div>
90
-
91
- <div className="relative lg:col-span-5">
92
- <FavButton className="absolute right-8 top-6 z-[20] sm:hidden" />
93
-
94
- <PluginModule
95
- component={Component.ProductImageSearchFeature}
96
- props={{
97
- product,
98
- activeIndex,
99
- showResetButton: true
100
- }}
101
- />
102
-
103
- <CarouselCore
104
- responsive={{
105
- all: {
106
- breakpoint: { max: 5000, min: 0 },
107
- items: 1
108
- }
109
- }}
110
- arrows={false}
111
- swipeable={true}
112
- ref={carouselRef}
113
- afterChange={(previousSlide, { currentSlide }) => {
114
- setActiveIndex(currentSlide);
115
- }}
116
- containerAspectRatio={{ mobile: 520 / 798, desktop: 484 / 726 }}
44
+ <div className="lg:grid lg:grid-cols-6">
45
+ <div className="lg:col-span-1">
46
+ <div className="flex flex-col items-center justify-center md:mr-[6px]">
47
+ <button
48
+ onClick={goToPrev}
49
+ className={twMerge(
50
+ 'hidden justify-center p-2 mb-3 border border-gray-100 rounded-full cursor-pointer lg:block',
51
+ [activeIndex === 0 && 'cursor-not-allowed opacity-45']
52
+ )}
53
+ disabled={activeIndex === 0}
117
54
  >
118
- {product?.productimage_set?.map((item, i) => (
55
+ <Icon name="chevron-up" size={15} className="fill-[#000000]" />
56
+ </button>
57
+ <div className="hidden flex-col items-center overflow-scroll w-[80px] max-h-[620px] lg:block">
58
+ {product?.productimage_set?.map((item, index) => (
119
59
  <Image
120
- key={i}
60
+ key={index}
121
61
  src={item.image}
122
- alt={product?.name || 'Product image'}
123
- draggable={false}
124
- aspectRatio={484 / 726}
125
- sizes="(min-width: 425px) 512px,
126
- (min-width: 601px) 576px,
127
- (min-width: 768px) 336px,
128
- (min-width: 1024px) 484px, 368px"
129
- fill
62
+ alt={`Thumbnail ${index}`}
63
+ width={80}
64
+ height={128}
65
+ className={twMerge('cursor-pointer', [
66
+ activeIndex === index && 'border-2 border-primary'
67
+ ])}
68
+ onClick={() => handleThumbnailClick(index)}
130
69
  />
131
70
  ))}
132
- </CarouselCore>
71
+ </div>
72
+ <button
73
+ onClick={goToNext}
74
+ className={twMerge(
75
+ 'hidden justify-center p-2 mt-3 border border-gray-100 rounded-full cursor-pointer lg:block',
76
+ [
77
+ activeIndex === product.productimage_set.length - 1 &&
78
+ 'cursor-not-allowed opacity-45'
79
+ ]
80
+ )}
81
+ disabled={activeIndex === product.productimage_set.length - 1}
82
+ >
83
+ <Icon name="chevron-down" size={15} className="fill-[#000000]" />
84
+ </button>
133
85
  </div>
134
86
  </div>
135
- </>
87
+
88
+ <div className="relative lg:col-span-5">
89
+ <FavButton className="absolute right-8 top-6 z-[20] sm:hidden" />
90
+
91
+ <CarouselCore
92
+ responsive={{
93
+ all: {
94
+ breakpoint: { max: 5000, min: 0 },
95
+ items: 1
96
+ }
97
+ }}
98
+ arrows={false}
99
+ swipeable={true}
100
+ ref={carouselRef}
101
+ afterChange={(previousSlide, { currentSlide }) => {
102
+ setActiveIndex(currentSlide);
103
+ }}
104
+ containerAspectRatio={{ mobile: 520 / 798, desktop: 484 / 726 }}
105
+ >
106
+ {product?.productimage_set?.map((item, i) => (
107
+ <Image
108
+ key={i}
109
+ src={item.image}
110
+ alt={product.name}
111
+ draggable={false}
112
+ aspectRatio={484 / 726}
113
+ sizes="(min-width: 425px) 512px,
114
+ (min-width: 601px) 576px,
115
+ (min-width: 768px) 336px,
116
+ (min-width: 1024px) 484px, 368px"
117
+ fill
118
+ />
119
+ ))}
120
+ </CarouselCore>
121
+ </div>
122
+ </div>
136
123
  );
137
124
  }
@@ -2,11 +2,11 @@
2
2
 
3
3
  import { yupResolver } from '@hookform/resolvers/yup';
4
4
  import clsx from 'clsx';
5
- import { signIn } from 'next-auth/react';
5
+ import { signIn, SignInOptions } from 'next-auth/react';
6
6
  import { useState } from 'react';
7
7
  import { SubmitHandler, useForm } from 'react-hook-form';
8
8
  import { useAppDispatch, useAppSelector } from '@akinon/next/redux/hooks';
9
- import { RegisterFormType, FormType, PzSignInOptions } from '@theme/types';
9
+ import { RegisterFormType } from '@theme/types';
10
10
  import { Button, Checkbox, Icon, Input, Modal } from '@theme/components';
11
11
  import * as yup from 'yup';
12
12
  import { useCaptcha, useLocalization, useRouter } from '@akinon/next/hooks';
@@ -125,9 +125,8 @@ export const Register = () => {
125
125
  redirect: false,
126
126
  callbackUrl: '/',
127
127
  captchaValidated,
128
- ...data,
129
- formType: FormType.register
130
- } as PzSignInOptions);
128
+ ...data
129
+ } as SignInOptions);
131
130
  };
132
131
 
133
132
  const onSubmit: SubmitHandler<RegisterFormType> = async (data) => {
@@ -144,6 +143,7 @@ export const Register = () => {
144
143
  if (registerResponse.error) {
145
144
  const errors: AuthError[] = JSON.parse(registerResponse.error);
146
145
 
146
+
147
147
  if (errors.find((error) => error.type === 'captcha')) {
148
148
  if (await validateCaptcha()) {
149
149
  onSubmit(data);
@@ -171,25 +171,25 @@ export const Register = () => {
171
171
  try {
172
172
  parsedValue = JSON.parse(item.value);
173
173
  } catch {
174
- parsedValue = [item.value];
174
+ parsedValue = [item.value];
175
175
  }
176
176
  } else {
177
- parsedValue = item.value;
177
+ parsedValue = item.value;
178
178
  }
179
179
 
180
180
  if (Array.isArray(parsedValue)) {
181
181
  setError(item.name as keyof RegisterFormType, {
182
182
  type: 'custom',
183
- message: parsedValue.join(', ')
183
+ message: parsedValue.join(', '),
184
184
  });
185
185
  } else {
186
186
  Object.keys(parsedValue).forEach((key) => {
187
187
  const fieldName = key as keyof RegisterFormType;
188
188
  const errorMessages = parsedValue[key] as string[];
189
-
189
+
190
190
  setError(fieldName, {
191
191
  type: 'custom',
192
- message: errorMessages.join(', ')
192
+ message: errorMessages.join(', '),
193
193
  });
194
194
  });
195
195
  }
@@ -247,11 +247,7 @@ export const Register = () => {
247
247
  </p>
248
248
 
249
249
  <form onSubmit={handleSubmit(onSubmit)} className="flex flex-col gap-4">
250
- <input
251
- type="hidden"
252
- value={FormType.register}
253
- {...register('formType')}
254
- />
250
+ <input type="hidden" value="register" {...register('formType')} />
255
251
  <input type="hidden" value={locale} {...register('locale')} />
256
252
 
257
253
  <div className={clsx({ 'mb-4': errors.email })}>
@@ -2,7 +2,6 @@ import 'server-only';
2
2
 
3
3
  import { Link, Accordion } from '@theme/components';
4
4
  import { getWidgetData } from '@akinon/next/data/server';
5
- import { ServerVariables } from '@akinon/next/utils/server-variables';
6
5
 
7
6
  type SideItem = {
8
7
  value: string;
@@ -48,7 +47,6 @@ type FooterMenuType = {
48
47
 
49
48
  export default async function FooterMenu() {
50
49
  const data = await getWidgetData<FooterMenuType>({ slug: 'footer-menu' });
51
- const { locale } = ServerVariables;
52
50
 
53
51
  return (
54
52
  <div className="flex-1">
@@ -74,7 +72,7 @@ export default async function FooterMenu() {
74
72
  : '_self'
75
73
  }
76
74
  data-testid={`footer-categories-${item?.value?.name
77
- ?.toLocaleLowerCase(locale)
75
+ ?.toLocaleLowerCase()
78
76
  .split(' ')
79
77
  .join('')}`}
80
78
  >
@@ -98,9 +96,7 @@ export default async function FooterMenu() {
98
96
  ? '_blank'
99
97
  : '_self'
100
98
  }
101
- data-testid={`footer-categories-${item?.value?.name?.toLocaleLowerCase(
102
- locale
103
- )}`}
99
+ data-testid={`footer-categories-${item?.value?.name?.toLocaleLowerCase()}`}
104
100
  >
105
101
  {item?.value?.name}
106
102
  </Link>