@akinon/next 1.103.0-rc.80 → 1.103.0-snapshot-ZERO-3648-20250930091244
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 +46 -1319
- package/__tests__/next-config.test.ts +10 -1
- package/api/virtual-try-on.ts +238 -0
- package/bin/pz-prebuild.js +0 -1
- package/components/accordion.tsx +5 -20
- package/components/file-input.tsx +3 -65
- package/components/input.tsx +0 -2
- package/components/link.tsx +12 -16
- package/components/modal.tsx +16 -32
- package/components/plugin-module.tsx +6 -29
- package/data/client/checkout.ts +3 -5
- package/data/server/category.ts +24 -44
- package/data/server/flatpage.ts +12 -16
- package/data/server/landingpage.ts +12 -16
- package/data/server/list.ts +13 -23
- package/data/server/special-page.ts +12 -16
- package/data/urls.ts +2 -6
- package/hocs/server/with-segment-defaults.tsx +2 -5
- package/hooks/use-localization.ts +3 -2
- package/middlewares/complete-gpay.ts +1 -2
- package/middlewares/complete-masterpass.ts +1 -2
- package/middlewares/default.ts +0 -50
- package/middlewares/locale.ts +1 -9
- package/middlewares/redirection-payment.ts +1 -2
- package/middlewares/saved-card-redirection.ts +1 -2
- package/middlewares/three-d-redirection.ts +2 -2
- package/middlewares/url-redirection.ts +14 -8
- package/package.json +2 -2
- package/plugins.d.ts +5 -8
- package/plugins.js +1 -2
- package/redux/middlewares/checkout.ts +2 -6
- package/types/commerce/order.ts +0 -1
- package/types/index.ts +1 -34
- package/utils/app-fetch.ts +2 -7
- package/utils/redirect.ts +3 -22
- package/with-pz-config.js +5 -1
- package/__tests__/redirect.test.ts +0 -319
- package/api/form.ts +0 -84
- package/api/image-proxy.ts +0 -75
- package/api/similar-product-list.ts +0 -84
- package/api/similar-products.ts +0 -120
- package/data/server/basket.ts +0 -72
- package/utils/redirect-ignore.ts +0 -35
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { resolve } from 'path';
|
|
2
2
|
import type { NextConfig } from 'next';
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
function findBaseDir() {
|
|
5
|
+
const insideNodeModules = __dirname.includes('node_modules');
|
|
6
|
+
|
|
7
|
+
if (insideNodeModules) {
|
|
8
|
+
return resolve(__dirname, '../../../../');
|
|
9
|
+
} else {
|
|
10
|
+
return resolve(__dirname, '../../../apps/projectzeronext');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
4
13
|
|
|
5
14
|
const baseDir = findBaseDir();
|
|
6
15
|
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
const VIRTUAL_TRY_ON_API_URL = process.env.NEXT_PUBLIC_VIRTUAL_TRY_ON_API_URL;
|
|
4
|
+
|
|
5
|
+
let limitedCategoriesCache: {
|
|
6
|
+
data: any;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
} | null = null;
|
|
9
|
+
|
|
10
|
+
const CACHE_TTL = 3600000;
|
|
11
|
+
|
|
12
|
+
export async function GET(request: NextRequest) {
|
|
13
|
+
try {
|
|
14
|
+
const { searchParams } = new URL(request.url);
|
|
15
|
+
const endpoint = searchParams.get('endpoint');
|
|
16
|
+
|
|
17
|
+
if (endpoint === 'limited-categories') {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
|
|
20
|
+
if (limitedCategoriesCache && (now - limitedCategoriesCache.timestamp) < CACHE_TTL) {
|
|
21
|
+
return NextResponse.json(limitedCategoriesCache.data, {
|
|
22
|
+
status: 200,
|
|
23
|
+
headers: {
|
|
24
|
+
'Access-Control-Allow-Origin': '*',
|
|
25
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
|
|
26
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization',
|
|
27
|
+
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
|
|
28
|
+
'X-Virtual-Try-On-Cache-Status': 'HIT'
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/limited-categories`;
|
|
34
|
+
|
|
35
|
+
const response = await fetch(externalUrl, {
|
|
36
|
+
method: 'GET',
|
|
37
|
+
headers: {
|
|
38
|
+
Accept: 'application/json',
|
|
39
|
+
...(request.headers.get('authorization') && {
|
|
40
|
+
Authorization: request.headers.get('authorization')!
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
let responseData: any;
|
|
46
|
+
const responseText = await response.text();
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
responseData = responseText ? JSON.parse(responseText) : {};
|
|
50
|
+
} catch (parseError) {
|
|
51
|
+
responseData = { category_ids: [] };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
responseData = { category_ids: [] };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
limitedCategoriesCache = {
|
|
59
|
+
data: responseData,
|
|
60
|
+
timestamp: Date.now()
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return NextResponse.json(responseData, {
|
|
64
|
+
status: response.ok ? response.status : 200,
|
|
65
|
+
headers: {
|
|
66
|
+
'Access-Control-Allow-Origin': '*',
|
|
67
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
|
|
68
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization',
|
|
69
|
+
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=7200',
|
|
70
|
+
'X-Virtual-Try-On-Cache-Status': 'MISS'
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return NextResponse.json(
|
|
76
|
+
{ error: 'Invalid endpoint for GET method' },
|
|
77
|
+
{ status: 400 }
|
|
78
|
+
);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
return NextResponse.json({ category_ids: [] }, { status: 200 });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export async function POST(request: NextRequest) {
|
|
85
|
+
try {
|
|
86
|
+
const { searchParams } = new URL(request.url);
|
|
87
|
+
const endpoint = searchParams.get('endpoint');
|
|
88
|
+
|
|
89
|
+
const body = await request.json();
|
|
90
|
+
|
|
91
|
+
let externalUrl: string;
|
|
92
|
+
if (endpoint === 'feedback') {
|
|
93
|
+
externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/feedback`;
|
|
94
|
+
} else {
|
|
95
|
+
externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/virtual-try-on`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const httpMethod = endpoint === 'feedback' ? 'PUT' : 'POST';
|
|
99
|
+
|
|
100
|
+
const response = await fetch(externalUrl, {
|
|
101
|
+
method: httpMethod,
|
|
102
|
+
headers: {
|
|
103
|
+
'Content-Type': 'application/json',
|
|
104
|
+
...(httpMethod === 'POST' && { Accept: 'application/json' }),
|
|
105
|
+
...(request.headers.get('authorization') && {
|
|
106
|
+
Authorization: request.headers.get('authorization')!
|
|
107
|
+
})
|
|
108
|
+
},
|
|
109
|
+
body: JSON.stringify(body)
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
let responseData: any;
|
|
113
|
+
const responseText = await response.text();
|
|
114
|
+
|
|
115
|
+
if (endpoint === 'feedback') {
|
|
116
|
+
try {
|
|
117
|
+
responseData = responseText ? JSON.parse(responseText) : {};
|
|
118
|
+
} catch (parseError) {
|
|
119
|
+
responseData = { error: 'Invalid JSON response from feedback API' };
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
try {
|
|
123
|
+
responseData = responseText ? JSON.parse(responseText) : {};
|
|
124
|
+
} catch (parseError) {
|
|
125
|
+
responseData = { error: 'Invalid JSON response' };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!response.ok && responseData.error) {
|
|
130
|
+
let userFriendlyMessage = responseData.error;
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
typeof responseData.error === 'string' &&
|
|
134
|
+
(responseData.error.includes('duplicate key value') ||
|
|
135
|
+
responseData.error.includes('image_pk'))
|
|
136
|
+
) {
|
|
137
|
+
userFriendlyMessage =
|
|
138
|
+
'This image has already been processed. Please try with a different image.';
|
|
139
|
+
} else if (responseData.error.includes('bulk insert images')) {
|
|
140
|
+
userFriendlyMessage =
|
|
141
|
+
'There was an issue processing your image. Please try again with a different image.';
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return NextResponse.json(
|
|
145
|
+
{
|
|
146
|
+
...responseData,
|
|
147
|
+
message: userFriendlyMessage
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
status: response.status,
|
|
151
|
+
headers: {
|
|
152
|
+
'Access-Control-Allow-Origin': '*',
|
|
153
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
154
|
+
'Access-Control-Allow-Headers':
|
|
155
|
+
'Content-Type, Accept, Authorization'
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return NextResponse.json(responseData, {
|
|
162
|
+
status: response.status,
|
|
163
|
+
headers: {
|
|
164
|
+
'Access-Control-Allow-Origin': '*',
|
|
165
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
166
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization'
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return NextResponse.json(
|
|
171
|
+
{
|
|
172
|
+
status: 'error',
|
|
173
|
+
message:
|
|
174
|
+
'Internal server error occurred during virtual try-on processing'
|
|
175
|
+
},
|
|
176
|
+
{ status: 500 }
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function PUT(request: NextRequest) {
|
|
182
|
+
try {
|
|
183
|
+
const { searchParams } = new URL(request.url);
|
|
184
|
+
const endpoint = searchParams.get('endpoint');
|
|
185
|
+
|
|
186
|
+
if (endpoint !== 'feedback') {
|
|
187
|
+
return NextResponse.json(
|
|
188
|
+
{ error: 'PUT method only supports feedback endpoint' },
|
|
189
|
+
{ status: 400 }
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const body = await request.json();
|
|
194
|
+
|
|
195
|
+
const externalUrl = `${VIRTUAL_TRY_ON_API_URL}/api/v1/feedback`;
|
|
196
|
+
|
|
197
|
+
const response = await fetch(externalUrl, {
|
|
198
|
+
method: 'PUT',
|
|
199
|
+
headers: {
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
...(request.headers.get('authorization') && {
|
|
202
|
+
Authorization: request.headers.get('authorization')!
|
|
203
|
+
})
|
|
204
|
+
},
|
|
205
|
+
body: JSON.stringify(body)
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const responseData = await response.json();
|
|
209
|
+
|
|
210
|
+
return NextResponse.json(responseData, {
|
|
211
|
+
status: response.status,
|
|
212
|
+
headers: {
|
|
213
|
+
'Access-Control-Allow-Origin': '*',
|
|
214
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
|
|
215
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization'
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
} catch (error) {
|
|
219
|
+
return NextResponse.json(
|
|
220
|
+
{
|
|
221
|
+
status: 'error',
|
|
222
|
+
message: 'Internal server error occurred during feedback submission'
|
|
223
|
+
},
|
|
224
|
+
{ status: 500 }
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export async function OPTIONS() {
|
|
230
|
+
return new NextResponse(null, {
|
|
231
|
+
status: 200,
|
|
232
|
+
headers: {
|
|
233
|
+
'Access-Control-Allow-Origin': '*',
|
|
234
|
+
'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
|
|
235
|
+
'Access-Control-Allow-Headers': 'Content-Type, Accept, Authorization'
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
package/bin/pz-prebuild.js
CHANGED
package/components/accordion.tsx
CHANGED
|
@@ -7,19 +7,15 @@ import { AccordionProps } from '../types';
|
|
|
7
7
|
|
|
8
8
|
export const Accordion = ({
|
|
9
9
|
isCollapse = false,
|
|
10
|
-
collapseClassName,
|
|
11
10
|
title,
|
|
12
11
|
subTitle,
|
|
13
12
|
icons = ['chevron-up', 'chevron-down'],
|
|
14
13
|
iconSize = 16,
|
|
15
14
|
iconColor = 'fill-[#000000]',
|
|
16
15
|
children,
|
|
17
|
-
headerClassName,
|
|
18
16
|
className,
|
|
19
17
|
titleClassName,
|
|
20
|
-
|
|
21
|
-
dataTestId,
|
|
22
|
-
contentClassName
|
|
18
|
+
dataTestId
|
|
23
19
|
}: AccordionProps) => {
|
|
24
20
|
const [collapse, setCollapse] = useState(isCollapse);
|
|
25
21
|
|
|
@@ -31,22 +27,15 @@ export const Accordion = ({
|
|
|
31
27
|
)}
|
|
32
28
|
>
|
|
33
29
|
<div
|
|
34
|
-
className=
|
|
35
|
-
'flex items-center justify-between cursor-pointer',
|
|
36
|
-
headerClassName
|
|
37
|
-
)}
|
|
30
|
+
className="flex items-center justify-between cursor-pointer"
|
|
38
31
|
onClick={() => setCollapse(!collapse)}
|
|
39
32
|
data-testid={dataTestId}
|
|
40
33
|
>
|
|
41
|
-
<div className=
|
|
34
|
+
<div className="flex flex-col">
|
|
42
35
|
{title && (
|
|
43
36
|
<h3 className={twMerge('text-sm', titleClassName)}>{title}</h3>
|
|
44
37
|
)}
|
|
45
|
-
{subTitle &&
|
|
46
|
-
<h4 className={twMerge('text-xs text-gray-700', subTitleClassName)}>
|
|
47
|
-
{subTitle}
|
|
48
|
-
</h4>
|
|
49
|
-
)}
|
|
38
|
+
{subTitle && <h4 className="text-xs text-gray-700">{subTitle}</h4>}
|
|
50
39
|
</div>
|
|
51
40
|
|
|
52
41
|
{icons && (
|
|
@@ -57,11 +46,7 @@ export const Accordion = ({
|
|
|
57
46
|
/>
|
|
58
47
|
)}
|
|
59
48
|
</div>
|
|
60
|
-
{collapse &&
|
|
61
|
-
<div className={twMerge('mt-3 text-sm', collapseClassName)}>
|
|
62
|
-
{children}
|
|
63
|
-
</div>
|
|
64
|
-
)}
|
|
49
|
+
{collapse && <div className="mt-3 text-sm">{children}</div>}
|
|
65
50
|
</div>
|
|
66
51
|
);
|
|
67
52
|
};
|
|
@@ -1,70 +1,8 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
1
|
import { forwardRef } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import { twMerge } from 'tailwind-merge';
|
|
5
|
-
import { FileInputProps } from '../types';
|
|
2
|
+
import { FileInputProps } from '../types/index';
|
|
6
3
|
|
|
7
4
|
export const FileInput = forwardRef<HTMLInputElement, FileInputProps>(
|
|
8
|
-
function
|
|
9
|
-
{
|
|
10
|
-
buttonClassName,
|
|
11
|
-
onChange,
|
|
12
|
-
fileClassName,
|
|
13
|
-
fileNameWrapperClassName,
|
|
14
|
-
fileInputClassName,
|
|
15
|
-
...props
|
|
16
|
-
},
|
|
17
|
-
ref
|
|
18
|
-
) {
|
|
19
|
-
const { t } = useLocalization();
|
|
20
|
-
const [fileNames, setFileNames] = useState<string[]>([]);
|
|
21
|
-
|
|
22
|
-
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
23
|
-
const files = Array.from(event.target.files || []);
|
|
24
|
-
setFileNames(files.map((file) => file.name));
|
|
25
|
-
|
|
26
|
-
if (onChange) {
|
|
27
|
-
onChange(event);
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
return (
|
|
32
|
-
<div className="relative">
|
|
33
|
-
<input
|
|
34
|
-
type="file"
|
|
35
|
-
{...props}
|
|
36
|
-
ref={ref}
|
|
37
|
-
className={twMerge(
|
|
38
|
-
'absolute inset-0 w-full h-full opacity-0 cursor-pointer',
|
|
39
|
-
fileInputClassName
|
|
40
|
-
)}
|
|
41
|
-
onChange={handleFileChange}
|
|
42
|
-
/>
|
|
43
|
-
<button
|
|
44
|
-
type="button"
|
|
45
|
-
className={twMerge(
|
|
46
|
-
'bg-primary text-white py-2 px-4 text-sm',
|
|
47
|
-
buttonClassName
|
|
48
|
-
)}
|
|
49
|
-
>
|
|
50
|
-
{t('common.file_input.select_file')}
|
|
51
|
-
</button>
|
|
52
|
-
<div
|
|
53
|
-
className={twMerge('mt-1 text-gray-500', fileNameWrapperClassName)}
|
|
54
|
-
>
|
|
55
|
-
{fileNames.length > 0 ? (
|
|
56
|
-
<ul className={twMerge('list-disc pl-4 text-xs', fileClassName)}>
|
|
57
|
-
{fileNames.map((name, index) => (
|
|
58
|
-
<li key={index}>{name}</li>
|
|
59
|
-
))}
|
|
60
|
-
</ul>
|
|
61
|
-
) : (
|
|
62
|
-
<span className={twMerge('text-xs', fileClassName)}>
|
|
63
|
-
{t('common.file_input.no_file')}
|
|
64
|
-
</span>
|
|
65
|
-
)}
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
);
|
|
5
|
+
function fileInput(props, ref) {
|
|
6
|
+
return <input type="file" {...props} ref={ref} />;
|
|
69
7
|
}
|
|
70
8
|
);
|
package/components/input.tsx
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import { forwardRef, FocusEvent, useState, Ref } from 'react';
|
|
3
3
|
import { Controller } from 'react-hook-form';
|
|
4
|
-
|
|
5
|
-
// @ts-ignore
|
|
6
4
|
import { PatternFormat, PatternFormatProps } from 'react-number-format';
|
|
7
5
|
import { InputProps } from '../types';
|
|
8
6
|
import { twMerge } from 'tailwind-merge';
|
package/components/link.tsx
CHANGED
|
@@ -10,9 +10,7 @@ type LinkProps = Omit<
|
|
|
10
10
|
React.AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
11
11
|
keyof NextLinkProps
|
|
12
12
|
> &
|
|
13
|
-
NextLinkProps
|
|
14
|
-
href: string;
|
|
15
|
-
};
|
|
13
|
+
NextLinkProps;
|
|
16
14
|
|
|
17
15
|
export const Link = ({ children, href, ...rest }: LinkProps) => {
|
|
18
16
|
const { locale, defaultLocaleValue, localeUrlStrategy } = useLocalization();
|
|
@@ -28,21 +26,19 @@ export const Link = ({ children, href, ...rest }: LinkProps) => {
|
|
|
28
26
|
return href;
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return hrefWithLocale;
|
|
42
|
-
}
|
|
29
|
+
const pathnameWithoutLocale = href.replace(urlLocaleMatcherRegex, '');
|
|
30
|
+
const hrefWithLocale = `/${locale}${pathnameWithoutLocale}`;
|
|
31
|
+
|
|
32
|
+
if (localeUrlStrategy === LocaleUrlStrategy.ShowAllLocales) {
|
|
33
|
+
return hrefWithLocale;
|
|
34
|
+
} else if (
|
|
35
|
+
localeUrlStrategy === LocaleUrlStrategy.HideDefaultLocale &&
|
|
36
|
+
locale !== defaultLocaleValue
|
|
37
|
+
) {
|
|
38
|
+
return hrefWithLocale;
|
|
43
39
|
}
|
|
44
40
|
|
|
45
|
-
return href;
|
|
41
|
+
return href || '#';
|
|
46
42
|
}, [href, defaultLocaleValue, locale, localeUrlStrategy]);
|
|
47
43
|
|
|
48
44
|
return (
|
package/components/modal.tsx
CHANGED
|
@@ -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>
|
|
@@ -21,9 +21,8 @@ enum Plugin {
|
|
|
21
21
|
Akifast = 'pz-akifast',
|
|
22
22
|
MultiBasket = 'pz-multi-basket',
|
|
23
23
|
SavedCard = 'pz-saved-card',
|
|
24
|
-
Hepsipay = 'pz-hepsipay',
|
|
25
24
|
FlowPayment = 'pz-flow-payment',
|
|
26
|
-
|
|
25
|
+
VirtualTryOn = 'pz-virtual-try-on'
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export enum Component {
|
|
@@ -49,16 +48,8 @@ export enum Component {
|
|
|
49
48
|
AkifastCheckoutButton = 'CheckoutButton',
|
|
50
49
|
MultiBasket = 'MultiBasket',
|
|
51
50
|
SavedCard = 'SavedCardOption',
|
|
52
|
-
Hepsipay = 'Hepsipay',
|
|
53
51
|
FlowPayment = 'FlowPayment',
|
|
54
|
-
|
|
55
|
-
SimilarProductsFilterSidebar = 'SimilarProductsFilterSidebar',
|
|
56
|
-
SimilarProductsResultsGrid = 'SimilarProductsResultsGrid',
|
|
57
|
-
SimilarProductsPlugin = 'SimilarProductsPlugin',
|
|
58
|
-
ProductImageSearchFeature = 'ProductImageSearchFeature',
|
|
59
|
-
ImageSearchButton = 'ImageSearchButton',
|
|
60
|
-
HeaderImageSearchFeature = 'HeaderImageSearchFeature',
|
|
61
|
-
IyzicoSavedCard = 'IyzicoSavedCardOption'
|
|
52
|
+
VirtualTryOnPlugin = 'VirtualTryOnPlugin'
|
|
62
53
|
}
|
|
63
54
|
|
|
64
55
|
const PluginComponents = new Map([
|
|
@@ -91,21 +82,9 @@ const PluginComponents = new Map([
|
|
|
91
82
|
[Component.AkifastQuickLoginButton, Component.AkifastCheckoutButton]
|
|
92
83
|
],
|
|
93
84
|
[Plugin.MultiBasket, [Component.MultiBasket]],
|
|
94
|
-
[Plugin.SavedCard, [Component.SavedCard
|
|
95
|
-
[Plugin.Hepsipay, [Component.Hepsipay]],
|
|
85
|
+
[Plugin.SavedCard, [Component.SavedCard]],
|
|
96
86
|
[Plugin.FlowPayment, [Component.FlowPayment]],
|
|
97
|
-
[
|
|
98
|
-
Plugin.SimilarProducts,
|
|
99
|
-
[
|
|
100
|
-
Component.SimilarProductsModal,
|
|
101
|
-
Component.SimilarProductsFilterSidebar,
|
|
102
|
-
Component.SimilarProductsResultsGrid,
|
|
103
|
-
Component.SimilarProductsPlugin,
|
|
104
|
-
Component.ProductImageSearchFeature,
|
|
105
|
-
Component.ImageSearchButton,
|
|
106
|
-
Component.HeaderImageSearchFeature
|
|
107
|
-
]
|
|
108
|
-
]
|
|
87
|
+
[Plugin.VirtualTryOn, [Component.VirtualTryOnPlugin]]
|
|
109
88
|
]);
|
|
110
89
|
|
|
111
90
|
const getPlugin = (component: Component) => {
|
|
@@ -170,12 +149,10 @@ export default function PluginModule({
|
|
|
170
149
|
promise = import(`${'@akinon/pz-multi-basket'}`);
|
|
171
150
|
} else if (plugin === Plugin.SavedCard) {
|
|
172
151
|
promise = import(`${'@akinon/pz-saved-card'}`);
|
|
173
|
-
} else if (plugin === Plugin.Hepsipay) {
|
|
174
|
-
promise = import(`${'@akinon/pz-hepsipay'}`);
|
|
175
152
|
} else if (plugin === Plugin.FlowPayment) {
|
|
176
153
|
promise = import(`${'@akinon/pz-flow-payment'}`);
|
|
177
|
-
} else if (plugin === Plugin.
|
|
178
|
-
promise = import(`${'@akinon/pz-
|
|
154
|
+
} else if (plugin === Plugin.VirtualTryOn) {
|
|
155
|
+
promise = import(`${'@akinon/pz-virtual-try-on'}`);
|
|
179
156
|
}
|
|
180
157
|
} catch (error) {
|
|
181
158
|
logger.error(error);
|
package/data/client/checkout.ts
CHANGED
|
@@ -35,10 +35,8 @@ import {
|
|
|
35
35
|
|
|
36
36
|
interface CheckoutResponse {
|
|
37
37
|
pre_order?: PreOrder;
|
|
38
|
-
errors
|
|
39
|
-
non_field_errors
|
|
40
|
-
sample_products?: string[];
|
|
41
|
-
[key: string]: string | string[] | undefined;
|
|
38
|
+
errors: {
|
|
39
|
+
non_field_errors: string;
|
|
42
40
|
};
|
|
43
41
|
context_list?: CheckoutContext[];
|
|
44
42
|
template_name?: string;
|
|
@@ -841,7 +839,7 @@ export const checkoutApi = api.injectEndpoints({
|
|
|
841
839
|
method: 'GET'
|
|
842
840
|
})
|
|
843
841
|
}),
|
|
844
|
-
setLoyaltyData: build.mutation<CheckoutResponse, number
|
|
842
|
+
setLoyaltyData: build.mutation<CheckoutResponse, number>({
|
|
845
843
|
query: (amount) => ({
|
|
846
844
|
url: buildClientRequestUrl(checkout.loyaltyCardPage, {
|
|
847
845
|
useFormData: true
|