@akinon/projectzero 1.101.0-rc.76 → 1.101.0-snapshot-ZERO-3615-20250924121313
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.
- package/CHANGELOG.md +5 -238
- package/app-template/.env.example +0 -1
- package/app-template/CHANGELOG.md +304 -5040
- package/app-template/README.md +1 -25
- package/app-template/package.json +19 -21
- package/app-template/public/locales/en/checkout.json +0 -6
- package/app-template/public/locales/en/common.json +1 -48
- package/app-template/public/locales/tr/checkout.json +0 -6
- package/app-template/public/locales/tr/common.json +1 -48
- package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
- package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +4 -17
- package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +1 -12
- package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +11 -29
- package/app-template/src/app/[commerce]/[locale]/[currency]/landing-page/[pk]/page.tsx +1 -12
- package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +10 -28
- package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +1 -12
- package/app-template/src/app/api/form/[...id]/route.ts +7 -1
- package/app-template/src/assets/fonts/pz-icon.css +0 -3
- package/app-template/src/components/__tests__/link.test.tsx +0 -2
- package/app-template/src/components/accordion.tsx +19 -22
- package/app-template/src/components/currency-select.tsx +0 -1
- package/app-template/src/components/file-input.tsx +7 -27
- package/app-template/src/components/generate-form-fields.tsx +4 -43
- package/app-template/src/components/input.tsx +2 -9
- package/app-template/src/components/modal.tsx +16 -32
- package/app-template/src/components/pagination.tsx +0 -1
- package/app-template/src/components/price.tsx +1 -1
- package/app-template/src/components/select.tsx +26 -38
- package/app-template/src/components/types/index.ts +1 -25
- package/app-template/src/hooks/index.ts +0 -2
- package/app-template/src/plugins.js +1 -3
- package/app-template/src/settings.js +2 -8
- package/app-template/src/types/index.ts +0 -17
- package/app-template/src/views/account/address-form.tsx +4 -8
- package/app-template/src/views/account/contact-form.tsx +1 -1
- package/app-template/src/views/account/content-header.tsx +2 -2
- package/app-template/src/views/account/faq/faq-tabs.tsx +2 -8
- package/app-template/src/views/basket/basket-item.tsx +14 -22
- package/app-template/src/views/basket/summary.tsx +7 -10
- package/app-template/src/views/breadcrumb.tsx +2 -2
- package/app-template/src/views/category/category-info.tsx +0 -1
- package/app-template/src/views/category/filters/index.tsx +1 -1
- package/app-template/src/views/checkout/summary.tsx +0 -10
- package/app-template/src/views/guest-login/index.tsx +1 -6
- package/app-template/src/views/header/action-menu.tsx +1 -1
- package/app-template/src/views/header/search/index.tsx +5 -17
- package/app-template/src/views/product/product-info.tsx +263 -62
- package/app-template/src/views/product/slider.tsx +73 -86
- package/app-template/src/widgets/footer-menu.tsx +2 -6
- package/commands/plugins.ts +16 -63
- package/dist/commands/plugins.js +16 -57
- package/package.json +1 -1
- package/app-template/.github/instructions/routing.instructions.md +0 -603
- package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/loading.tsx +0 -67
- package/app-template/src/app/api/image-proxy/route.ts +0 -1
- package/app-template/src/app/api/similar-product-list/route.ts +0 -1
- package/app-template/src/app/api/similar-products/route.ts +0 -1
- package/app-template/src/hooks/use-product-cart.ts +0 -77
- package/app-template/src/hooks/use-stock-alert.ts +0 -74
- package/app-template/src/utils/variant-validation.ts +0 -41
- package/app-template/src/views/basket/basket-content.tsx +0 -106
- package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +0 -121
- package/app-template/src/views/product/product-actions.tsx +0 -165
- package/app-template/src/views/product/product-share.tsx +0 -56
- package/app-template/src/views/product/product-variants.tsx +0 -26
|
@@ -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
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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=
|
|
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={
|
|
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=
|
|
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=
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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={
|
|
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=
|
|
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>
|
|
@@ -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
|
-
)
|
|
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={
|
|
24
|
-
|
|
25
|
-
|
|
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=
|
|
35
|
+
<span className="mb-1">
|
|
40
36
|
{label} {required && <span className="text-secondary">*</span>}
|
|
41
37
|
</span>
|
|
42
38
|
)}
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
)}
|
|
@@ -29,13 +29,7 @@ export interface PaginationProps {
|
|
|
29
29
|
isLoading?: boolean;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export
|
|
33
|
-
fileClassName?: string;
|
|
34
|
-
fileNameWrapperClassName?: string;
|
|
35
|
-
fileInputClassName?: string;
|
|
36
|
-
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
37
|
-
buttonClassName?: string;
|
|
38
|
-
}
|
|
32
|
+
export type FileInputProps = React.HTMLProps<HTMLInputElement>;
|
|
39
33
|
|
|
40
34
|
export type RadioProps = React.HTMLProps<HTMLInputElement>;
|
|
41
35
|
|
|
@@ -64,7 +58,6 @@ export interface SelectProps extends React.HTMLProps<HTMLSelectElement> {
|
|
|
64
58
|
iconSize?: number;
|
|
65
59
|
error?: FieldError | undefined;
|
|
66
60
|
required?: boolean;
|
|
67
|
-
labelClassName?: string;
|
|
68
61
|
}
|
|
69
62
|
export interface IconProps extends React.ComponentPropsWithRef<'i'> {
|
|
70
63
|
name: string;
|
|
@@ -98,20 +91,3 @@ export interface BadgeProps {
|
|
|
98
91
|
children: ReactNode;
|
|
99
92
|
className?: string;
|
|
100
93
|
}
|
|
101
|
-
|
|
102
|
-
export type AccordionProps = {
|
|
103
|
-
isCollapse?: boolean;
|
|
104
|
-
collapseClassName?: string;
|
|
105
|
-
title?: string;
|
|
106
|
-
subTitle?: string;
|
|
107
|
-
icons?: string[];
|
|
108
|
-
iconSize?: number;
|
|
109
|
-
iconColor?: string;
|
|
110
|
-
children?: ReactNode;
|
|
111
|
-
headerClassName?: string;
|
|
112
|
-
className?: string;
|
|
113
|
-
titleClassName?: string;
|
|
114
|
-
subTitleClassName?: string;
|
|
115
|
-
dataTestId?: string;
|
|
116
|
-
contentClassName?: string;
|
|
117
|
-
};
|
|
@@ -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,
|
|
44
|
+
localeUrlStrategy: LocaleUrlStrategy.HideDefaultLocale,
|
|
50
45
|
redirectToDefaultLocale: true,
|
|
51
46
|
defaultCurrencyCode: 'usd'
|
|
52
47
|
},
|
|
@@ -67,6 +62,5 @@ module.exports = {
|
|
|
67
62
|
redis: {
|
|
68
63
|
defaultExpirationTime: 900 // 15 min
|
|
69
64
|
},
|
|
70
|
-
customNotFoundEnabled: false
|
|
71
|
-
commerceRedirectionIgnoreList: ['/users/reset']
|
|
65
|
+
customNotFoundEnabled: false
|
|
72
66
|
};
|
|
@@ -125,20 +125,3 @@ export interface SeoProps {
|
|
|
125
125
|
ogPriceAmount?: string;
|
|
126
126
|
ogPriceCurrency?: string;
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
export interface ModalProps {
|
|
130
|
-
portalId: string;
|
|
131
|
-
children?: React.ReactNode;
|
|
132
|
-
open?: boolean;
|
|
133
|
-
setOpen?: (open: boolean) => void;
|
|
134
|
-
title?: React.ReactNode;
|
|
135
|
-
showCloseButton?: React.ReactNode;
|
|
136
|
-
className?: string;
|
|
137
|
-
overlayClassName?: string;
|
|
138
|
-
headerWrapperClassName?: string;
|
|
139
|
-
titleClassName?: string;
|
|
140
|
-
closeButtonClassName?: string;
|
|
141
|
-
iconName?: string;
|
|
142
|
-
iconSize?: number;
|
|
143
|
-
iconClassName?: string;
|
|
144
|
-
}
|
|
@@ -259,25 +259,23 @@ export const AddressForm = (props: Props) => {
|
|
|
259
259
|
{/* TODO: Fix select and textarea components */}
|
|
260
260
|
|
|
261
261
|
<Select
|
|
262
|
-
className="w-full border-gray-500 text-sm"
|
|
262
|
+
className="w-full border-gray-500 text-sm mt-2"
|
|
263
263
|
options={countryOptions}
|
|
264
264
|
{...register('country')}
|
|
265
265
|
error={errors.country}
|
|
266
266
|
data-testid="address-form-country"
|
|
267
267
|
label={t('account.address_book.form.country.title')}
|
|
268
|
-
labelClassName="mb-3"
|
|
269
268
|
required
|
|
270
269
|
/>
|
|
271
270
|
|
|
272
271
|
{city && (
|
|
273
272
|
<Select
|
|
274
|
-
className="w-full border-gray-500 text-sm"
|
|
273
|
+
className="w-full border-gray-500 text-sm mt-2"
|
|
275
274
|
options={cityOptions}
|
|
276
275
|
{...register('city')}
|
|
277
276
|
error={errors.city}
|
|
278
277
|
data-testid="address-form-city"
|
|
279
278
|
label={t('account.address_book.form.province.title')}
|
|
280
|
-
labelClassName="mb-3"
|
|
281
279
|
required
|
|
282
280
|
/>
|
|
283
281
|
)}
|
|
@@ -285,26 +283,24 @@ export const AddressForm = (props: Props) => {
|
|
|
285
283
|
<div className="flex gap-4">
|
|
286
284
|
<div className="flex-1">
|
|
287
285
|
<Select
|
|
288
|
-
className="w-full border-gray-500 text-sm"
|
|
286
|
+
className="w-full border-gray-500 text-sm mt-2"
|
|
289
287
|
options={townshipOptions}
|
|
290
288
|
{...register('township')}
|
|
291
289
|
error={errors.township}
|
|
292
290
|
data-testid="address-form-township"
|
|
293
291
|
label={t('account.address_book.form.township.title')}
|
|
294
|
-
labelClassName="mb-3"
|
|
295
292
|
required
|
|
296
293
|
/>
|
|
297
294
|
</div>
|
|
298
295
|
{district && (
|
|
299
296
|
<div className="flex-1">
|
|
300
297
|
<Select
|
|
301
|
-
className="w-full border-gray-500 text-sm"
|
|
298
|
+
className="w-full border-gray-500 text-sm mt-2"
|
|
302
299
|
options={districtOptions}
|
|
303
300
|
{...register('district')}
|
|
304
301
|
error={errors.district}
|
|
305
302
|
data-testid="address-form-district"
|
|
306
303
|
label={t('account.address_book.form.district.title')}
|
|
307
|
-
labelClassName="mb-3"
|
|
308
304
|
required
|
|
309
305
|
/>
|
|
310
306
|
</div>
|
|
@@ -111,7 +111,7 @@ const ContactForm = () => {
|
|
|
111
111
|
resolver: yupResolver(contactFormSchema(t))
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
const onSubmit: SubmitHandler<ContactFormType> = (data) => {
|
|
114
|
+
const onSubmit: SubmitHandler<ContactFormType> = (data, event) => {
|
|
115
115
|
const formData = new FormData();
|
|
116
116
|
|
|
117
117
|
Object.keys(data ?? {}).forEach((key) => {
|
|
@@ -31,13 +31,13 @@ export const ContentHeader = (props: Props) => {
|
|
|
31
31
|
</h3>
|
|
32
32
|
<Select
|
|
33
33
|
onChange={handleChange}
|
|
34
|
-
className="w-full mb-4 md:mb-0 md:w-56 text-xs"
|
|
34
|
+
className="w-full mb-4 md:mb-0 md:w-56 md:mr-4 text-xs"
|
|
35
35
|
options={orders}
|
|
36
36
|
data-testid="account-orders-header-select"
|
|
37
37
|
></Select>
|
|
38
38
|
<Button
|
|
39
39
|
className={clsx(
|
|
40
|
-
'w-full md:w-56
|
|
40
|
+
'w-full md:w-56',
|
|
41
41
|
isButtonDisabled &&
|
|
42
42
|
'hover:bg-black hover:text-white disabled:opacity-75'
|
|
43
43
|
)}
|