@akinon/projectzero 1.77.0 → 1.78.0-rc.1
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 +9 -0
- package/app-template/.gitignore +2 -0
- package/app-template/CHANGELOG.md +2655 -124
- package/app-template/package.json +18 -18
- package/app-template/public/locales/en/common.json +4 -0
- package/app-template/public/locales/tr/common.json +4 -0
- package/app-template/src/app/[commerce]/[locale]/[currency]/account/orders/[id]/cancellation/page.tsx +94 -5
- package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +9 -82
- package/app-template/src/app/[commerce]/[locale]/[currency]/orders/checkout/page.tsx +7 -4
- package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +8 -0
- package/app-template/src/components/button.tsx +50 -35
- package/app-template/src/components/file-input.tsx +44 -2
- package/app-template/src/components/types/index.ts +4 -1
- package/app-template/src/components/widget/widget-placeholder.tsx +12 -0
- package/app-template/src/middleware.ts +1 -0
- package/app-template/src/settings.js +6 -1
- package/app-template/src/views/account/address-form.tsx +2 -2
- package/app-template/src/views/account/contact-form.tsx +3 -8
- package/app-template/src/views/account/orders/order-cancellation-item.tsx +4 -3
- package/app-template/src/views/basket/basket-content.tsx +106 -0
- package/app-template/src/views/basket/basket-item.tsx +16 -13
- package/app-template/src/views/basket/summary.tsx +10 -7
- package/app-template/src/views/login/index.tsx +28 -4
- package/app-template/src/views/register/index.tsx +30 -5
- package/package.json +1 -1
- package/app-template/sentry.edge.config.ts +0 -3
- package/app-template/sentry.server.config.ts +0 -3
|
@@ -8,7 +8,8 @@ export const OrderCancellationItem = ({
|
|
|
8
8
|
item,
|
|
9
9
|
value,
|
|
10
10
|
onChange,
|
|
11
|
-
selectOption
|
|
11
|
+
selectOption,
|
|
12
|
+
fileInput
|
|
12
13
|
}) => {
|
|
13
14
|
const { t } = useLocalization();
|
|
14
15
|
const checkboxStatus =
|
|
@@ -38,7 +39,6 @@ export const OrderCancellationItem = ({
|
|
|
38
39
|
<div className="flex flex-wrap justify-between border-gray border-b mb-4 pb-3">
|
|
39
40
|
<div className="flex gap-3 mb-5 lg:mb-0">
|
|
40
41
|
{checkboxStatus && (
|
|
41
|
-
// TODO: Static image will change (TR)
|
|
42
42
|
<Checkbox
|
|
43
43
|
className="m-auto"
|
|
44
44
|
data-testid="account-orders-return-checkbox"
|
|
@@ -80,7 +80,7 @@ export const OrderCancellationItem = ({
|
|
|
80
80
|
</div>
|
|
81
81
|
</div>
|
|
82
82
|
</div>
|
|
83
|
-
<div className="flex flex-wrap justify-between w-full items-start lg:items-center lg:w-
|
|
83
|
+
<div className="flex flex-wrap justify-between w-full items-start lg:items-center lg:w-80 gap-4">
|
|
84
84
|
<div className="w-full flex flex-col lg:items-center lg:flex-row">
|
|
85
85
|
{item.active_cancellation_request?.easy_return?.code && (
|
|
86
86
|
<div className="flex items-center">
|
|
@@ -93,6 +93,7 @@ export const OrderCancellationItem = ({
|
|
|
93
93
|
|
|
94
94
|
{selectOption}
|
|
95
95
|
</div>
|
|
96
|
+
<div>{fileInput}</div>
|
|
96
97
|
</div>
|
|
97
98
|
</div>
|
|
98
99
|
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
4
|
+
import { Basket } from '@akinon/next/types';
|
|
5
|
+
import { Button, LoaderSpinner, Link } from '@theme/components';
|
|
6
|
+
import { BasketItem, Summary } from '@theme/views/basket';
|
|
7
|
+
import { ROUTES } from '@theme/routes';
|
|
8
|
+
import PluginModule, { Component } from '@akinon/next/components/plugin-module';
|
|
9
|
+
import { useEffect, useState } from 'react';
|
|
10
|
+
import { pushCartView } from '@theme/utils/gtm';
|
|
11
|
+
|
|
12
|
+
interface BasketContentProps {
|
|
13
|
+
initialBasket: Basket;
|
|
14
|
+
multiBasket: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function BasketContent({
|
|
18
|
+
initialBasket,
|
|
19
|
+
multiBasket
|
|
20
|
+
}: BasketContentProps) {
|
|
21
|
+
const { t } = useLocalization();
|
|
22
|
+
const [basket, setBasket] = useState<Basket>(initialBasket);
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (basket) {
|
|
26
|
+
const products = basket.basketitem_set.map((basketItem) => ({
|
|
27
|
+
...basketItem.product
|
|
28
|
+
}));
|
|
29
|
+
pushCartView(products);
|
|
30
|
+
}
|
|
31
|
+
}, [basket]);
|
|
32
|
+
|
|
33
|
+
const handleBasketUpdate = (updatedBasket: Basket) => {
|
|
34
|
+
setBasket(updatedBasket);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (!basket) {
|
|
38
|
+
return (
|
|
39
|
+
<div className="flex justify-center w-full">
|
|
40
|
+
<LoaderSpinner />
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<div className="max-w-screen-xl p-4 flex flex-col text-primary-800 lg:p-8 xl:flex-row xl:mx-auto">
|
|
47
|
+
{basket.basketitem_set && basket.basketitem_set.length > 0 ? (
|
|
48
|
+
<>
|
|
49
|
+
<div className="flex-1 xl:mr-16">
|
|
50
|
+
<div className="flex items-center justify-between py-2 border-b border-gray-200 lg:py-3">
|
|
51
|
+
<h2 className="text-xl lg:text-2xl font-light">
|
|
52
|
+
{t('basket.my_cart')}
|
|
53
|
+
</h2>
|
|
54
|
+
<Link
|
|
55
|
+
href={ROUTES.HOME}
|
|
56
|
+
className="text-xs hover:text-secondary-500"
|
|
57
|
+
>
|
|
58
|
+
{t('basket.back_to_shopping')}
|
|
59
|
+
</Link>
|
|
60
|
+
</div>
|
|
61
|
+
<ul>
|
|
62
|
+
{multiBasket ? (
|
|
63
|
+
<PluginModule
|
|
64
|
+
component={Component.MultiBasket}
|
|
65
|
+
props={{
|
|
66
|
+
BasketItem,
|
|
67
|
+
onBasketUpdate: handleBasketUpdate
|
|
68
|
+
}}
|
|
69
|
+
/>
|
|
70
|
+
) : (
|
|
71
|
+
basket.basketitem_set.map((basketItem, index) => (
|
|
72
|
+
<BasketItem
|
|
73
|
+
key={index}
|
|
74
|
+
basketItem={basketItem}
|
|
75
|
+
onBasketUpdate={handleBasketUpdate}
|
|
76
|
+
/>
|
|
77
|
+
))
|
|
78
|
+
)}
|
|
79
|
+
</ul>
|
|
80
|
+
</div>
|
|
81
|
+
<Summary basket={basket} onBasketUpdate={handleBasketUpdate} />
|
|
82
|
+
</>
|
|
83
|
+
) : (
|
|
84
|
+
<div className="flex flex-col items-center container max-w-screen-sm py-4 px-4 xs:py-6 xs:px-6 sm:py-8 sm:px-8 lg:max-w-screen-xl">
|
|
85
|
+
<h1
|
|
86
|
+
className="w-full text-xl font-light text-secondary text-center sm:text-2xl"
|
|
87
|
+
data-testid="basket-empty"
|
|
88
|
+
>
|
|
89
|
+
{t('basket.empty.title')}
|
|
90
|
+
</h1>
|
|
91
|
+
|
|
92
|
+
<div className="w-full text-sm text-black-800 text-center my-4 mb-2 sm:text-base">
|
|
93
|
+
<p>{t('basket.empty.content_first')}</p>
|
|
94
|
+
<p>{t('basket.empty.content_second')}.</p>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<Link href={ROUTES.HOME} passHref>
|
|
98
|
+
<Button className="px-10 mt-2" appearance="filled">
|
|
99
|
+
{t('basket.empty.button')}
|
|
100
|
+
</Button>
|
|
101
|
+
</Link>
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
useUpdateQuantityMutation
|
|
4
4
|
} from '@akinon/next/data/client/basket';
|
|
5
5
|
import { useAppDispatch } from '@akinon/next/redux/hooks';
|
|
6
|
-
import { BasketItem as BasketItemType } from '@akinon/next/types';
|
|
6
|
+
import { Basket, BasketItem as BasketItemType } from '@akinon/next/types';
|
|
7
7
|
import { Price, Button, Icon, Modal, Select, Link } from '@theme/components';
|
|
8
8
|
import { useState } from 'react';
|
|
9
9
|
import { useAddFavoriteMutation } from '@akinon/next/data/client/wishlist';
|
|
@@ -19,11 +19,12 @@ import { pushRemoveFromCart } from '@theme/utils/gtm';
|
|
|
19
19
|
interface Props {
|
|
20
20
|
basketItem?: BasketItemType;
|
|
21
21
|
namespace?: string;
|
|
22
|
+
onBasketUpdate?: (basket: Basket) => void;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export const BasketItem = (props: Props) => {
|
|
25
26
|
const { t } = useLocalization();
|
|
26
|
-
const { basketItem, namespace } = props;
|
|
27
|
+
const { basketItem, namespace, onBasketUpdate } = props;
|
|
27
28
|
const [updateQuantityMutation] = useUpdateQuantityMutation();
|
|
28
29
|
const dispatch = useAppDispatch();
|
|
29
30
|
const [isRemoveBasketModalOpen, setRemoveBasketModalOpen] = useState(false);
|
|
@@ -49,19 +50,21 @@ export const BasketItem = (props: Props) => {
|
|
|
49
50
|
requestParams.namespace = namespace;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
.unwrap()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
(draftBasket)
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
)
|
|
53
|
+
try {
|
|
54
|
+
const response = await updateQuantityMutation(requestParams).unwrap();
|
|
55
|
+
dispatch(
|
|
56
|
+
basketApi.util.updateQueryData(
|
|
57
|
+
'getBasket',
|
|
58
|
+
undefined,
|
|
59
|
+
(draftBasket) => {
|
|
60
|
+
Object.assign(draftBasket, response.basket);
|
|
61
|
+
}
|
|
63
62
|
)
|
|
64
63
|
);
|
|
64
|
+
onBasketUpdate?.(response.basket);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Error updating quantity:', error);
|
|
67
|
+
}
|
|
65
68
|
};
|
|
66
69
|
|
|
67
70
|
const deleteProduct = async (productPk?: number) => {
|
|
@@ -18,6 +18,7 @@ import clsx from 'clsx';
|
|
|
18
18
|
|
|
19
19
|
interface Props {
|
|
20
20
|
basket: Basket;
|
|
21
|
+
onBasketUpdate?: (basket: Basket) => void;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const voucherCodeFormSchema = (t) =>
|
|
@@ -27,7 +28,7 @@ const voucherCodeFormSchema = (t) =>
|
|
|
27
28
|
|
|
28
29
|
export const Summary = (props: Props) => {
|
|
29
30
|
const { t } = useLocalization();
|
|
30
|
-
const { basket } = props;
|
|
31
|
+
const { basket, onBasketUpdate } = props;
|
|
31
32
|
const router = useRouter();
|
|
32
33
|
const {
|
|
33
34
|
register,
|
|
@@ -53,7 +54,7 @@ export const Summary = (props: Props) => {
|
|
|
53
54
|
const removeVoucherCode = () => {
|
|
54
55
|
removeVoucherCodeMutation()
|
|
55
56
|
.unwrap()
|
|
56
|
-
.then((basket) =>
|
|
57
|
+
.then((basket) => {
|
|
57
58
|
dispatch(
|
|
58
59
|
basketApi.util.updateQueryData(
|
|
59
60
|
'getBasket',
|
|
@@ -62,8 +63,9 @@ export const Summary = (props: Props) => {
|
|
|
62
63
|
Object.assign(draftBasket, basket);
|
|
63
64
|
}
|
|
64
65
|
)
|
|
65
|
-
)
|
|
66
|
-
|
|
66
|
+
);
|
|
67
|
+
onBasketUpdate?.(basket);
|
|
68
|
+
})
|
|
67
69
|
.catch((error: Error) => {
|
|
68
70
|
setError('voucherCode', { message: error.data.non_field_errors });
|
|
69
71
|
});
|
|
@@ -74,7 +76,7 @@ export const Summary = (props: Props) => {
|
|
|
74
76
|
voucher_code: data.voucherCode
|
|
75
77
|
})
|
|
76
78
|
.unwrap()
|
|
77
|
-
.then((basket) =>
|
|
79
|
+
.then((basket) => {
|
|
78
80
|
dispatch(
|
|
79
81
|
basketApi.util.updateQueryData(
|
|
80
82
|
'getBasket',
|
|
@@ -83,8 +85,9 @@ export const Summary = (props: Props) => {
|
|
|
83
85
|
Object.assign(draftBasket, basket);
|
|
84
86
|
}
|
|
85
87
|
)
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
+
);
|
|
89
|
+
onBasketUpdate?.(basket);
|
|
90
|
+
})
|
|
88
91
|
.catch((error: Error) => {
|
|
89
92
|
setError('voucherCode', { message: error.data.non_field_errors });
|
|
90
93
|
});
|
|
@@ -103,10 +103,34 @@ export const Login = () => {
|
|
|
103
103
|
)?.data as string[];
|
|
104
104
|
|
|
105
105
|
fieldErrors?.forEach((item) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
let parsedValue: Record<string, string[]> | string[] = [];
|
|
107
|
+
|
|
108
|
+
if (typeof item.value === 'string') {
|
|
109
|
+
try {
|
|
110
|
+
parsedValue = JSON.parse(item.value);
|
|
111
|
+
} catch {
|
|
112
|
+
parsedValue = [item.value];
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
parsedValue = item.value;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (Array.isArray(parsedValue)) {
|
|
119
|
+
setError(item.name as keyof LoginFormType, {
|
|
120
|
+
type: 'custom',
|
|
121
|
+
message: parsedValue.join(', '),
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
Object.keys(parsedValue).forEach((key) => {
|
|
125
|
+
const fieldName = key as keyof LoginFormType;
|
|
126
|
+
const errorMessages = parsedValue[key] as string[];
|
|
127
|
+
|
|
128
|
+
setError(fieldName, {
|
|
129
|
+
type: 'custom',
|
|
130
|
+
message: errorMessages.join(', '),
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
110
134
|
});
|
|
111
135
|
|
|
112
136
|
if (nonFieldErrors?.length) {
|
|
@@ -143,6 +143,7 @@ export const Register = () => {
|
|
|
143
143
|
if (registerResponse.error) {
|
|
144
144
|
const errors: AuthError[] = JSON.parse(registerResponse.error);
|
|
145
145
|
|
|
146
|
+
|
|
146
147
|
if (errors.find((error) => error.type === 'captcha')) {
|
|
147
148
|
if (await validateCaptcha()) {
|
|
148
149
|
onSubmit(data);
|
|
@@ -164,10 +165,34 @@ export const Register = () => {
|
|
|
164
165
|
)?.data as string[];
|
|
165
166
|
|
|
166
167
|
fieldErrors?.forEach((item) => {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
let parsedValue: Record<string, string[]> | string[] = [];
|
|
169
|
+
|
|
170
|
+
if (typeof item.value === 'string') {
|
|
171
|
+
try {
|
|
172
|
+
parsedValue = JSON.parse(item.value);
|
|
173
|
+
} catch {
|
|
174
|
+
parsedValue = [item.value];
|
|
175
|
+
}
|
|
176
|
+
} else {
|
|
177
|
+
parsedValue = item.value;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (Array.isArray(parsedValue)) {
|
|
181
|
+
setError(item.name as keyof RegisterFormType, {
|
|
182
|
+
type: 'custom',
|
|
183
|
+
message: parsedValue.join(', '),
|
|
184
|
+
});
|
|
185
|
+
} else {
|
|
186
|
+
Object.keys(parsedValue).forEach((key) => {
|
|
187
|
+
const fieldName = key as keyof RegisterFormType;
|
|
188
|
+
const errorMessages = parsedValue[key] as string[];
|
|
189
|
+
|
|
190
|
+
setError(fieldName, {
|
|
191
|
+
type: 'custom',
|
|
192
|
+
message: errorMessages.join(', '),
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
}
|
|
171
196
|
});
|
|
172
197
|
|
|
173
198
|
if (nonFieldErrors?.length) {
|
|
@@ -303,7 +328,7 @@ export const Register = () => {
|
|
|
303
328
|
labelStyle="floating"
|
|
304
329
|
label={t('auth.register.form.phone.placeholder')}
|
|
305
330
|
className="h-14"
|
|
306
|
-
format={user_phone_format.replace(
|
|
331
|
+
format={user_phone_format.replace(/9/g, '#')}
|
|
307
332
|
allowEmptyFormatting
|
|
308
333
|
mask="_"
|
|
309
334
|
control={control}
|
package/package.json
CHANGED