@akinon/projectzero 1.102.0-rc.79 → 1.102.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 (66) hide show
  1. package/CHANGELOG.md +5 -236
  2. package/app-template/.env.example +0 -1
  3. package/app-template/CHANGELOG.md +330 -5014
  4. package/app-template/README.md +1 -25
  5. package/app-template/package.json +19 -21
  6. package/app-template/public/locales/en/checkout.json +0 -6
  7. package/app-template/public/locales/en/common.json +1 -48
  8. package/app-template/public/locales/tr/checkout.json +0 -6
  9. package/app-template/public/locales/tr/common.json +1 -48
  10. package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
  11. package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +11 -16
  12. package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +11 -17
  13. package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +38 -36
  14. package/app-template/src/app/[commerce]/[locale]/[currency]/landing-page/[pk]/page.tsx +1 -12
  15. package/app-template/src/app/[commerce]/[locale]/[currency]/{pz-not-found/page.tsx → not-found.tsx} +5 -7
  16. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +48 -46
  17. package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +20 -21
  18. package/app-template/src/app/api/form/[...id]/route.ts +7 -1
  19. package/app-template/src/assets/fonts/pz-icon.css +0 -3
  20. package/app-template/src/components/__tests__/link.test.tsx +0 -2
  21. package/app-template/src/components/accordion.tsx +19 -22
  22. package/app-template/src/components/currency-select.tsx +0 -1
  23. package/app-template/src/components/file-input.tsx +7 -27
  24. package/app-template/src/components/generate-form-fields.tsx +4 -43
  25. package/app-template/src/components/input.tsx +2 -9
  26. package/app-template/src/components/modal.tsx +16 -32
  27. package/app-template/src/components/pagination.tsx +0 -1
  28. package/app-template/src/components/price.tsx +1 -1
  29. package/app-template/src/components/select.tsx +26 -38
  30. package/app-template/src/components/types/index.ts +1 -25
  31. package/app-template/src/hooks/index.ts +0 -2
  32. package/app-template/src/plugins.js +1 -3
  33. package/app-template/src/settings.js +2 -8
  34. package/app-template/src/types/index.ts +0 -17
  35. package/app-template/src/views/account/address-form.tsx +4 -8
  36. package/app-template/src/views/account/contact-form.tsx +1 -1
  37. package/app-template/src/views/account/content-header.tsx +2 -2
  38. package/app-template/src/views/account/faq/faq-tabs.tsx +2 -8
  39. package/app-template/src/views/basket/basket-item.tsx +14 -22
  40. package/app-template/src/views/basket/summary.tsx +7 -10
  41. package/app-template/src/views/breadcrumb.tsx +2 -2
  42. package/app-template/src/views/category/category-info.tsx +0 -1
  43. package/app-template/src/views/category/filters/index.tsx +1 -1
  44. package/app-template/src/views/checkout/summary.tsx +0 -10
  45. package/app-template/src/views/guest-login/index.tsx +1 -6
  46. package/app-template/src/views/header/action-menu.tsx +1 -1
  47. package/app-template/src/views/header/search/index.tsx +5 -17
  48. package/app-template/src/views/product/product-info.tsx +263 -62
  49. package/app-template/src/views/product/slider.tsx +73 -86
  50. package/app-template/src/widgets/footer-menu.tsx +2 -6
  51. package/commands/plugins.ts +16 -63
  52. package/dist/commands/plugins.js +16 -57
  53. package/package.json +1 -1
  54. package/app-template/.github/instructions/routing.instructions.md +0 -603
  55. package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
  56. package/app-template/src/app/api/image-proxy/route.ts +0 -1
  57. package/app-template/src/app/api/similar-product-list/route.ts +0 -1
  58. package/app-template/src/app/api/similar-products/route.ts +0 -1
  59. package/app-template/src/hooks/use-product-cart.ts +0 -77
  60. package/app-template/src/hooks/use-stock-alert.ts +0 -74
  61. package/app-template/src/utils/variant-validation.ts +0 -41
  62. package/app-template/src/views/basket/basket-content.tsx +0 -106
  63. package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +0 -121
  64. package/app-template/src/views/product/product-actions.tsx +0 -165
  65. package/app-template/src/views/product/product-share.tsx +0 -56
  66. package/app-template/src/views/product/product-variants.tsx +0 -26
@@ -13,87 +13,89 @@ export async function generateMetadata({
13
13
  let result: Metadata = {};
14
14
 
15
15
  try {
16
- const productData = await getProductData({
16
+ const { data } = await getProductData({
17
17
  pk: params.pk,
18
18
  searchParams
19
19
  });
20
20
 
21
- if (!productData || !productData.data || !productData.data.product) {
22
- return result;
23
- }
21
+ const product = data?.product;
24
22
 
25
- const { product } = productData.data;
23
+ if (!product) {
24
+ return {};
25
+ }
26
26
 
27
27
  result = {
28
28
  title: product.name,
29
- description: String(product.attributes.description),
29
+ description: String(product.attributes?.description),
30
30
  twitter: {
31
31
  title: product.name,
32
- description: String(product.attributes.description)
32
+ description: String(product.attributes?.description)
33
33
  },
34
34
  openGraph: {
35
35
  title: product.name,
36
- description: String(product.attributes.description),
36
+ description: String(product.attributes?.description),
37
37
  images: product.productimage_set?.map((item) => ({
38
38
  url: item.image
39
39
  }))
40
40
  }
41
41
  };
42
- // eslint-disable-next-line no-empty
43
- } catch (error) {}
42
+ } catch (error: unknown) {
43
+ if ((error as Error & { status?: number })?.status === 404) {
44
+ notFound();
45
+ }
46
+ throw error;
47
+ }
44
48
 
45
49
  return result;
46
50
  }
47
51
 
48
52
  async function Page({ params, searchParams }: PageProps<{ pk: number }>) {
49
- let productData;
50
- let deliveryReturn;
53
+ if (params.pk === undefined || isNaN(Number(params.pk))) {
54
+ notFound();
55
+ }
51
56
 
52
57
  try {
53
- [productData, deliveryReturn] = await Promise.all([
58
+ const [{ data, breadcrumbData }, deliveryReturn] = await Promise.all([
54
59
  getProductData({
55
60
  pk: params.pk,
56
61
  searchParams
57
62
  }),
58
63
  getWidgetData({ slug: 'product-delivery-returns' })
59
64
  ]);
60
- } catch (error) {
61
- return notFound();
62
- }
63
-
64
- // If product data is not found, return 404
65
- if (!productData || !productData.data || !productData.data.product) {
66
- return notFound();
67
- }
68
65
 
69
- const { data, breadcrumbData } = productData;
70
- const jsonLd = generateJsonLd(data.product);
66
+ const jsonLd = generateJsonLd(data.product);
71
67
 
72
- return (
73
- <>
74
- <ProductLayout data={data} breadcrumbData={breadcrumbData}>
75
- <div className="flex flex-col items-center">
76
- <h1
77
- className="mt-4 text-2xl text-center md:mt-0"
78
- data-testid="product-name"
79
- >
80
- {data.product.name}
81
- </h1>
68
+ return (
69
+ <>
70
+ <ProductLayout data={data} breadcrumbData={breadcrumbData}>
71
+ <div className="flex flex-col items-center">
72
+ <h1
73
+ className="mt-4 text-2xl text-center md:mt-0"
74
+ data-testid="product-name"
75
+ >
76
+ {data.product.name}
77
+ </h1>
82
78
 
83
- <ProductInfo data={data} />
79
+ <ProductInfo data={data} />
84
80
 
85
- <AccordionWrapper
86
- data={data}
87
- deliveryReturn={deliveryReturn?.attributes}
88
- />
89
- </div>
90
- </ProductLayout>
91
- <script
92
- type="application/ld+json"
93
- dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
94
- />
95
- </>
96
- );
81
+ <AccordionWrapper
82
+ data={data}
83
+ deliveryReturn={deliveryReturn?.attributes}
84
+ />
85
+ </div>
86
+ </ProductLayout>
87
+ <script
88
+ type="application/ld+json"
89
+ dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
90
+ />
91
+ </>
92
+ );
93
+ } catch (error: unknown) {
94
+ if ((error as Error & { status?: number })?.status === 404) {
95
+ notFound();
96
+ }
97
+ throw error;
98
+ }
97
99
  }
98
100
 
99
101
  export default withSegmentDefaults(Page, { segmentType: 'page' });
@@ -7,30 +7,29 @@ import SpecialPageCarousel from '@theme/widgets/special-page-carousel';
7
7
  import { notFound } from 'next/navigation';
8
8
 
9
9
  async function Page({ params, searchParams }: PageProps<{ pk: number }>) {
10
- let data;
11
-
12
10
  try {
13
- data = await getSpecialPageData({ pk: params.pk, searchParams });
14
- } catch (error) {
15
- return notFound();
16
- }
11
+ const data = await getSpecialPageData({ pk: params.pk, searchParams });
17
12
 
18
- if (!data) {
19
- return notFound();
13
+ return (
14
+ <>
15
+ <CategoryLayout data={data}>
16
+ {data.special_page && (
17
+ <>
18
+ <SpecialPageBanner data={data.special_page} />
19
+ <SpecialPageCarousel
20
+ slug={data.special_page.video_embedded_code}
21
+ />
22
+ </>
23
+ )}
24
+ </CategoryLayout>
25
+ </>
26
+ );
27
+ } catch (error: unknown) {
28
+ if ((error as Error & { status?: number })?.status === 404) {
29
+ notFound();
30
+ }
31
+ throw error;
20
32
  }
21
-
22
- return (
23
- <>
24
- <CategoryLayout data={data}>
25
- {data.special_page && (
26
- <>
27
- <SpecialPageBanner data={data.special_page} />
28
- <SpecialPageCarousel slug={data.special_page.video_embedded_code} />
29
- </>
30
- )}
31
- </CategoryLayout>
32
- </>
33
- );
34
33
  }
35
34
 
36
35
  export default withSegmentDefaults(Page, { segmentType: 'page' });
@@ -1 +1,7 @@
1
- export * from '@akinon/next/api/form';
1
+ import { NextResponse } from 'next/server';
2
+
3
+ export async function POST() {
4
+ // TODO: Handle Form Data
5
+
6
+ return NextResponse.json({ message: 'ok' });
7
+ }
@@ -152,6 +152,3 @@ url("./pz-icon.svg?db4ba799c4ca72f4bb855458e0cd19ee#pz-icon") format("svg");
152
152
  .pz-icon-whatsapp:before {
153
153
  content: "\f12c";
154
154
  }
155
- .pz-icon-camera:before {
156
- content: "\f12d";
157
- }
@@ -30,8 +30,6 @@ describe('Link Component', () => {
30
30
  wrapper = container;
31
31
  });
32
32
 
33
- wrapper;
34
-
35
33
  it('should render without error', () => {
36
34
  const link = screen.getByRole('link');
37
35
 
@@ -1,25 +1,33 @@
1
1
  'use client';
2
2
 
3
- import { useState } from 'react';
3
+ import { ReactNode, useState } from 'react';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
- import { AccordionProps } from './types';
6
+
7
+ type AccordionProps = {
8
+ isCollapse?: boolean;
9
+ title?: string;
10
+ subTitle?: string;
11
+ icons?: string[];
12
+ iconSize?: number;
13
+ iconColor?: string;
14
+ children?: ReactNode;
15
+ className?: string;
16
+ titleClassName?: string;
17
+ dataTestId?: string;
18
+ };
7
19
 
8
20
  export const Accordion = ({
9
21
  isCollapse = false,
10
- collapseClassName,
11
22
  title,
12
23
  subTitle,
13
24
  icons = ['chevron-up', 'chevron-down'],
14
25
  iconSize = 16,
15
26
  iconColor = 'fill-[#000000]',
16
27
  children,
17
- headerClassName,
18
28
  className,
19
29
  titleClassName,
20
- subTitleClassName,
21
- dataTestId,
22
- contentClassName
30
+ dataTestId
23
31
  }: AccordionProps) => {
24
32
  const [collapse, setCollapse] = useState(isCollapse);
25
33
 
@@ -31,22 +39,15 @@ export const Accordion = ({
31
39
  )}
32
40
  >
33
41
  <div
34
- className={twMerge(
35
- 'flex items-center justify-between cursor-pointer',
36
- headerClassName
37
- )}
42
+ className="flex items-center justify-between cursor-pointer"
38
43
  onClick={() => setCollapse(!collapse)}
39
44
  data-testid={dataTestId}
40
45
  >
41
- <div className={twMerge('flex flex-col', contentClassName)}>
46
+ <div className="flex flex-col">
42
47
  {title && (
43
48
  <h3 className={twMerge('text-sm', titleClassName)}>{title}</h3>
44
49
  )}
45
- {subTitle && (
46
- <h4 className={twMerge('text-xs text-gray-700', subTitleClassName)}>
47
- {subTitle}
48
- </h4>
49
- )}
50
+ {subTitle && <h4 className="text-xs text-gray-700">{subTitle}</h4>}
50
51
  </div>
51
52
 
52
53
  {icons && (
@@ -57,11 +58,7 @@ export const Accordion = ({
57
58
  />
58
59
  )}
59
60
  </div>
60
- {collapse && (
61
- <div className={twMerge('mt-3 text-sm', collapseClassName)}>
62
- {children}
63
- </div>
64
- )}
61
+ {collapse && <div className="mt-3 text-sm">{children}</div>}
65
62
  </div>
66
63
  );
67
64
  };
@@ -70,7 +70,6 @@ export const CurrencySelect = (props: CurrencySelectProps) => {
70
70
  onClick={confirmModalHandleClick}
71
71
  appearance="filled"
72
72
  className="font-medium px-10 py-4 h-12"
73
- data-testid="currency-modal-confirm"
74
73
  >
75
74
  {t('common.currency_modal.continue')}
76
75
  </Button>
@@ -1,21 +1,11 @@
1
1
  import { useState } from 'react';
2
2
  import { forwardRef } from 'react';
3
3
  import { FileInputProps } from '@theme/components/types';
4
+ import clsx from 'clsx';
4
5
  import { useLocalization } from '@akinon/next/hooks';
5
- import { twMerge } from 'tailwind-merge';
6
6
 
7
7
  export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
8
- function FileInput(
9
- {
10
- buttonClassName,
11
- onChange,
12
- fileClassName,
13
- fileNameWrapperClassName,
14
- fileInputClassName,
15
- ...props
16
- },
17
- ref
18
- ) {
8
+ function FileInput({ className, onChange, ...props }, ref) {
19
9
  const { t } = useLocalization();
20
10
  const [fileNames, setFileNames] = useState<string[]>([]);
21
11
 
@@ -34,34 +24,24 @@ export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
34
24
  type="file"
35
25
  {...props}
36
26
  ref={ref}
37
- className={twMerge(
38
- 'absolute inset-0 w-full h-full opacity-0 cursor-pointer',
39
- fileInputClassName
40
- )}
27
+ className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
41
28
  onChange={handleFileChange}
42
29
  />
43
30
  <button
44
31
  type="button"
45
- className={twMerge(
46
- 'bg-primary text-white py-2 px-4 text-sm',
47
- buttonClassName
48
- )}
32
+ className={clsx('bg-primary text-white py-2 px-4 text-sm', className)}
49
33
  >
50
34
  {t('common.file_input.select_file')}
51
35
  </button>
52
- <div
53
- className={twMerge('mt-1 text-gray-500', fileNameWrapperClassName)}
54
- >
36
+ <div className="mt-1 text-gray-500">
55
37
  {fileNames.length > 0 ? (
56
- <ul className={twMerge('list-disc pl-4 text-xs', fileClassName)}>
38
+ <ul className="list-disc pl-4 text-xs">
57
39
  {fileNames.map((name, index) => (
58
40
  <li key={index}>{name}</li>
59
41
  ))}
60
42
  </ul>
61
43
  ) : (
62
- <span className={twMerge('text-xs', fileClassName)}>
63
- {t('common.file_input.no_file')}
64
- </span>
44
+ <span className="text-xs">{t('common.file_input.no_file')}</span>
65
45
  )}
66
46
  </div>
67
47
  </div>
@@ -7,7 +7,6 @@ import { useForm } from 'react-hook-form';
7
7
  import { yupResolver } from '@hookform/resolvers/yup';
8
8
  import * as yup from 'yup';
9
9
  import DynamicForm from './dynamic-form';
10
-
11
10
  import {
12
11
  AllFieldClassesType,
13
12
  FieldPropertiesType,
@@ -15,7 +14,6 @@ import {
15
14
  FormPropertiesType,
16
15
  Schema
17
16
  } from '@akinon/next/types';
18
- import { useLocalization } from '@akinon/next/hooks';
19
17
 
20
18
  export function GenerateFormFields({
21
19
  schema,
@@ -30,14 +28,8 @@ export function GenerateFormFields({
30
28
  formProperties: FormPropertiesType;
31
29
  submitButtonText: string;
32
30
  }) {
33
- const { t } = useLocalization();
34
31
  const [fields, setFields] = useState([]);
35
32
  const [loading, setIsLoading] = useState(true);
36
- const [isSubmitting, setIsSubmitting] = useState(false);
37
- const [submitStatus, setSubmitStatus] = useState<
38
- 'idle' | 'success' | 'error'
39
- >('idle');
40
- const [submitMessage, setSubmitMessage] = useState('');
41
33
 
42
34
  const generateValidationSchema = () => {
43
35
  const schemaObject = {};
@@ -88,7 +80,6 @@ export function GenerateFormFields({
88
80
  const {
89
81
  handleSubmit,
90
82
  register,
91
- reset,
92
83
  formState: { errors }
93
84
  } = useForm<FormField>({
94
85
  resolver: yupResolver(generateValidationSchema())
@@ -117,10 +108,6 @@ export function GenerateFormFields({
117
108
  }, [schema, fieldProperties]);
118
109
 
119
110
  const onSubmit = async (data) => {
120
- setIsSubmitting(true);
121
- setSubmitStatus('idle');
122
- setSubmitMessage('');
123
-
124
111
  try {
125
112
  const formData = new FormData();
126
113
 
@@ -128,25 +115,12 @@ export function GenerateFormFields({
128
115
  formData.append(key, data[key]);
129
116
  });
130
117
 
131
- const response = await fetch(formProperties.actionUrl, {
118
+ fetch(formProperties.actionUrl, {
132
119
  method: 'POST',
133
120
  body: formData
134
121
  });
135
-
136
- if (response.ok) {
137
- setSubmitStatus('success');
138
- setSubmitMessage(t('common.forms.success'));
139
- reset();
140
- } else {
141
- setSubmitStatus('error');
142
- setSubmitMessage(t('common.forms.error'));
143
- }
144
122
  } catch (error) {
145
- console.error(t('common.forms.submit_error'), error);
146
- setSubmitStatus('error');
147
- setSubmitMessage(t('common.forms.error'));
148
- } finally {
149
- setIsSubmitting(false);
123
+ console.error('Form submit error:', error);
150
124
  }
151
125
  };
152
126
 
@@ -363,22 +337,9 @@ export function GenerateFormFields({
363
337
  <LoaderSpinner />
364
338
  ) : (
365
339
  <>
366
- {submitStatus === 'success' && (
367
- <div className="mb-4 p-3 bg-green-100 border border-green-400 text-green-700 rounded">
368
- {submitMessage}
369
- </div>
370
- )}
371
-
372
- {submitStatus === 'error' && (
373
- <div className="mb-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
374
- {submitMessage}
375
- </div>
376
- )}
377
-
378
340
  {fields.map((field: FormField) => generateField(field))}
379
-
380
- <Button type="submit" className="w-full" disabled={isSubmitting}>
381
- {isSubmitting ? t('common.forms.sending') : submitButtonText}
341
+ <Button type="submit" className="w-full">
342
+ {submitButtonText}
382
343
  </Button>
383
344
  </>
384
345
  )}
@@ -48,13 +48,7 @@ export const Input = forwardRef<
48
48
  props.className
49
49
  );
50
50
 
51
- const inputProps: {
52
- id?: string;
53
- ref?: Ref<HTMLInputElement>;
54
- className?: string;
55
- onFocus?: () => void;
56
- onBlur?: (event: FocusEvent<HTMLInputElement>) => void;
57
- } = {
51
+ const inputProps: any = {
58
52
  id,
59
53
  ref,
60
54
  className: inputClass,
@@ -78,8 +72,7 @@ export const Input = forwardRef<
78
72
  hasFloatingLabel,
79
73
  'mb-2': !hasFloatingLabel,
80
74
  '-translate-y-2 bg-white inline-flex h-auto':
81
- hasFloatingLabel &&
82
- (focused || hasValue || props.value || props.format)
75
+ hasFloatingLabel && (focused || hasValue)
83
76
  })
84
77
  )}
85
78
  >
@@ -4,7 +4,16 @@ import ReactPortal from './react-portal';
4
4
  import { Icon } from './icon';
5
5
  import { twMerge } from 'tailwind-merge';
6
6
  import { useEffect } from 'react';
7
- import { ModalProps } from '@theme/types';
7
+
8
+ export interface ModalProps {
9
+ portalId: string;
10
+ children?: React.ReactNode;
11
+ open?: boolean;
12
+ setOpen?: (open: boolean) => void;
13
+ title?: React.ReactNode;
14
+ showCloseButton?: React.ReactNode;
15
+ className?: string;
16
+ }
8
17
 
9
18
  export const Modal = (props: ModalProps) => {
10
19
  const {
@@ -14,14 +23,7 @@ export const Modal = (props: ModalProps) => {
14
23
  setOpen,
15
24
  title = '',
16
25
  showCloseButton = true,
17
- className,
18
- overlayClassName,
19
- headerWrapperClassName,
20
- titleClassName,
21
- closeButtonClassName,
22
- iconName = 'close',
23
- iconSize = 16,
24
- iconClassName
26
+ className
25
27
  } = props;
26
28
 
27
29
  useEffect(() => {
@@ -36,12 +38,7 @@ export const Modal = (props: ModalProps) => {
36
38
 
37
39
  return (
38
40
  <ReactPortal wrapperId={portalId}>
39
- <div
40
- className={twMerge(
41
- 'fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50',
42
- overlayClassName
43
- )}
44
- />
41
+ <div className="fixed top-0 left-0 w-screen h-screen bg-primary bg-opacity-60 z-50" />
45
42
  <section
46
43
  className={twMerge(
47
44
  'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white',
@@ -49,28 +46,15 @@ export const Modal = (props: ModalProps) => {
49
46
  )}
50
47
  >
51
48
  {(showCloseButton || title) && (
52
- <div
53
- className={twMerge(
54
- 'flex px-6 py-4 border-b border-gray-400',
55
- headerWrapperClassName
56
- )}
57
- >
58
- {title && (
59
- <h3 className={twMerge('text-lg font-light', titleClassName)}>
60
- {title}
61
- </h3>
62
- )}
49
+ <div className="flex px-6 py-4 border-b border-gray-400">
50
+ {title && <h3 className="text-lg font-light">{title}</h3>}
63
51
  {showCloseButton && (
64
52
  <button
65
53
  type="button"
66
54
  onClick={() => setOpen(false)}
67
- className={twMerge('ml-auto', closeButtonClassName)}
55
+ className="ml-auto"
68
56
  >
69
- <Icon
70
- name={iconName}
71
- size={iconSize}
72
- className={iconClassName}
73
- />
57
+ <Icon name="close" size={16} />
74
58
  </button>
75
59
  )}
76
60
  </div>
@@ -125,7 +125,6 @@ export const Pagination = (props: PaginationProps) => {
125
125
  setPrevPage(1);
126
126
  setNextPage(1);
127
127
  }
128
- // eslint-disable-next-line react-hooks/exhaustive-deps
129
128
  }, [page]);
130
129
 
131
130
  useEffect(() => {
@@ -56,7 +56,7 @@ export const Price = (props: NumericFormatProps & PriceProps) => {
56
56
 
57
57
  const currentCurrencyDecimalScale = Settings.localization.currencies.find(
58
58
  (currency) => currency.code === currencyCode_
59
- )?.decimalScale;
59
+ ).decimalScale;
60
60
 
61
61
  return (
62
62
  <NumericFormat
@@ -14,18 +14,14 @@ const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
14
14
  error,
15
15
  label,
16
16
  required = false,
17
- labelClassName,
18
17
  ...rest
19
18
  } = props;
20
19
 
21
20
  return (
22
21
  <label
23
- className={twMerge(
24
- clsx('flex flex-col relative text-xs text-gray-800', {
25
- 'pl-7': icon
26
- }),
27
- labelClassName
28
- )}
22
+ className={clsx('flex flex-col relative text-xs text-gray-800', {
23
+ 'pl-7': icon
24
+ })}
29
25
  >
30
26
  {icon && (
31
27
  <Icon
@@ -36,40 +32,32 @@ const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
36
32
  )}
37
33
 
38
34
  {label && (
39
- <span className={twMerge('mb-1', labelClassName)}>
35
+ <span className="mb-1">
40
36
  {label} {required && <span className="text-secondary">*</span>}
41
37
  </span>
42
38
  )}
43
- <div className="relative">
44
- <select
45
- {...rest}
46
- ref={ref}
47
- className={twMerge(
48
- clsx(
49
- 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-none',
50
- !borderless &&
51
- 'border border-gray-200 transition-all duration-150 hover:border-primary',
52
- 'appearance-none bg-transparent'
53
- ),
54
- className
55
- )}
56
- >
57
- {options?.map((option) => (
58
- <option
59
- key={option.value}
60
- value={option.value}
61
- className={option.class}
62
- >
63
- {option.label}
64
- </option>
65
- ))}
66
- </select>
67
- <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700">
68
- <svg className="h-4 w-4 fill-current" viewBox="0 0 20 20">
69
- <path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" />
70
- </svg>
71
- </div>
72
- </div>
39
+ <select
40
+ {...rest}
41
+ ref={ref}
42
+ className={twMerge(
43
+ clsx(
44
+ 'cursor-pointer truncate h-10 w-40 px-2.5 shrink-0 outline-none',
45
+ !borderless &&
46
+ 'border border-gray-200 transition-all duration-150 hover:border-primary'
47
+ ),
48
+ className
49
+ )}
50
+ >
51
+ {options?.map((option) => (
52
+ <option
53
+ key={option.value}
54
+ value={option.value}
55
+ className={option.class}
56
+ >
57
+ {option.label}
58
+ </option>
59
+ ))}
60
+ </select>
73
61
  {error && (
74
62
  <span className="mt-1 text-sm text-error">{error.message}</span>
75
63
  )}