@akinon/projectzero 1.104.0-rc.83 → 1.104.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.
- package/CHANGELOG.md +5 -233
- package/app-template/.env.example +0 -1
- package/app-template/CHANGELOG.md +325 -4954
- package/app-template/README.md +1 -25
- package/app-template/package.json +19 -19
- package/app-template/public/locales/en/checkout.json +0 -6
- package/app-template/public/locales/en/common.json +1 -42
- package/app-template/public/locales/tr/checkout.json +0 -6
- package/app-template/public/locales/tr/common.json +1 -42
- package/app-template/src/app/[commerce]/[locale]/[currency]/basket/page.tsx +82 -9
- package/app-template/src/app/[commerce]/[locale]/[currency]/landing-page/[pk]/page.tsx +1 -12
- 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/file-input.tsx +7 -27
- 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 +1 -6
- 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/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/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
package/commands/plugins.ts
CHANGED
|
@@ -29,14 +29,7 @@ async function checkVersion(pkg: PackageJson) {
|
|
|
29
29
|
|
|
30
30
|
if (!semver.satisfies(pkg.dependencies['@akinon/next'], latestVersion)) {
|
|
31
31
|
console.warn(
|
|
32
|
-
`\x1b[
|
|
33
|
-
`\x1b[41m version ${pkg.dependencies['@akinon/next']}`,
|
|
34
|
-
`\x1b[43m Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`,
|
|
35
|
-
'\x1b[0m\n'
|
|
36
|
-
);
|
|
37
|
-
} else {
|
|
38
|
-
console.log(
|
|
39
|
-
`\x1b[42m Info: The package "${packageName}" is currently in the current version (${latestVersion}).`,
|
|
32
|
+
`\x1b[43mWarning: The "${packageName}" package is currently at version ${pkg.dependencies['@akinon/next']}. Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`,
|
|
40
33
|
'\x1b[0m\n'
|
|
41
34
|
);
|
|
42
35
|
}
|
|
@@ -61,27 +54,7 @@ export default async () => {
|
|
|
61
54
|
}
|
|
62
55
|
}
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
const packageJsonPaths = [
|
|
66
|
-
path.resolve(rootDir, './package.json'),
|
|
67
|
-
path.resolve(rootDir, './apps/projectzeronext/package.json')
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
for (const packageJsonPath of packageJsonPaths) {
|
|
71
|
-
try {
|
|
72
|
-
const pkg = require(packageJsonPath);
|
|
73
|
-
if (pkg.dependencies['@akinon/next']) {
|
|
74
|
-
return pkg;
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
continue;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
throw new Error('Could not find package.json with @akinon/next dependency');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const pkg = findPackageJson();
|
|
57
|
+
const pkg: PackageJson = require(path.resolve(rootDir, './package.json'));
|
|
85
58
|
await checkVersion(pkg);
|
|
86
59
|
|
|
87
60
|
const pluginsFilePath = findPluginsFilePath();
|
|
@@ -96,65 +69,45 @@ export default async () => {
|
|
|
96
69
|
}
|
|
97
70
|
|
|
98
71
|
const definedPlugins = [
|
|
99
|
-
{
|
|
100
|
-
name: 'Akifast',
|
|
101
|
-
value: 'pz-akifast'
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
name: 'Apple Pay',
|
|
105
|
-
value: 'pz-apple-pay'
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
name: 'B2B',
|
|
109
|
-
value: 'pz-b2b'
|
|
110
|
-
},
|
|
111
72
|
{
|
|
112
73
|
name: 'Basket Gift Pack',
|
|
113
74
|
value: 'pz-basket-gift-pack'
|
|
114
75
|
},
|
|
115
76
|
{
|
|
116
|
-
name: '
|
|
117
|
-
value: 'pz-
|
|
77
|
+
name: 'Click & Collect',
|
|
78
|
+
value: 'pz-click-collect'
|
|
118
79
|
},
|
|
119
80
|
{
|
|
120
81
|
name: 'Checkout Gift Pack',
|
|
121
82
|
value: 'pz-checkout-gift-pack'
|
|
122
83
|
},
|
|
123
84
|
{
|
|
124
|
-
name: 'Click
|
|
125
|
-
value: 'pz-click-
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
name: 'Credit Payment',
|
|
129
|
-
value: 'pz-credit-payment'
|
|
85
|
+
name: 'One Click Checkout',
|
|
86
|
+
value: 'pz-one-click-checkout'
|
|
130
87
|
},
|
|
131
88
|
{
|
|
132
89
|
name: 'Garanti Pay',
|
|
133
90
|
value: 'pz-gpay'
|
|
134
91
|
},
|
|
135
92
|
{
|
|
136
|
-
name: '
|
|
137
|
-
value: 'pz-
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
name: 'Multi Basket',
|
|
141
|
-
value: 'pz-multi-basket'
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
name: 'One Click Checkout',
|
|
145
|
-
value: 'pz-one-click-checkout'
|
|
93
|
+
name: 'Pay On Delivery',
|
|
94
|
+
value: 'pz-pay-on-delivery'
|
|
146
95
|
},
|
|
147
96
|
{
|
|
148
97
|
name: 'Otp',
|
|
149
98
|
value: 'pz-otp'
|
|
150
99
|
},
|
|
151
100
|
{
|
|
152
|
-
name: '
|
|
153
|
-
value: 'pz-
|
|
101
|
+
name: 'BKM Express',
|
|
102
|
+
value: 'pz-bkm'
|
|
154
103
|
},
|
|
155
104
|
{
|
|
156
|
-
name: '
|
|
157
|
-
value: 'pz-
|
|
105
|
+
name: 'Credit Payment',
|
|
106
|
+
value: 'pz-credit-payment'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'Multi Basket',
|
|
110
|
+
value: 'pz-multi-basket'
|
|
158
111
|
},
|
|
159
112
|
{
|
|
160
113
|
name: 'Tabby Payment Extension',
|
package/dist/commands/plugins.js
CHANGED
|
@@ -50,10 +50,7 @@ function checkVersion(pkg) {
|
|
|
50
50
|
const pkgInfo = (yield response.json());
|
|
51
51
|
const latestVersion = pkgInfo['dist-tags'].latest;
|
|
52
52
|
if (!semver_1.default.satisfies(pkg.dependencies['@akinon/next'], latestVersion)) {
|
|
53
|
-
console.warn(`\x1b[
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
console.log(`\x1b[42m Info: The package "${packageName}" is currently in the current version (${latestVersion}).`, '\x1b[0m\n');
|
|
53
|
+
console.warn(`\x1b[43mWarning: The "${packageName}" package is currently at version ${pkg.dependencies['@akinon/next']}. Please upgrade it to the latest version (${latestVersion}) to ensure plugin compatibility.`, '\x1b[0m\n');
|
|
57
54
|
}
|
|
58
55
|
}
|
|
59
56
|
catch (error) {
|
|
@@ -75,25 +72,7 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
75
72
|
throw new Error('plugins.js was not found in either of the expected locations.');
|
|
76
73
|
}
|
|
77
74
|
}
|
|
78
|
-
|
|
79
|
-
const packageJsonPaths = [
|
|
80
|
-
path_1.default.resolve(rootDir, './package.json'),
|
|
81
|
-
path_1.default.resolve(rootDir, './apps/projectzeronext/package.json')
|
|
82
|
-
];
|
|
83
|
-
for (const packageJsonPath of packageJsonPaths) {
|
|
84
|
-
try {
|
|
85
|
-
const pkg = require(packageJsonPath);
|
|
86
|
-
if (pkg.dependencies['@akinon/next']) {
|
|
87
|
-
return pkg;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
throw new Error('Could not find package.json with @akinon/next dependency');
|
|
95
|
-
}
|
|
96
|
-
const pkg = findPackageJson();
|
|
75
|
+
const pkg = require(path_1.default.resolve(rootDir, './package.json'));
|
|
97
76
|
yield checkVersion(pkg);
|
|
98
77
|
const pluginsFilePath = findPluginsFilePath();
|
|
99
78
|
let installedPlugins = [];
|
|
@@ -105,65 +84,45 @@ exports.default = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
105
84
|
process.exit(1);
|
|
106
85
|
}
|
|
107
86
|
const definedPlugins = [
|
|
108
|
-
{
|
|
109
|
-
name: 'Akifast',
|
|
110
|
-
value: 'pz-akifast'
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
name: 'Apple Pay',
|
|
114
|
-
value: 'pz-apple-pay'
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
name: 'B2B',
|
|
118
|
-
value: 'pz-b2b'
|
|
119
|
-
},
|
|
120
87
|
{
|
|
121
88
|
name: 'Basket Gift Pack',
|
|
122
89
|
value: 'pz-basket-gift-pack'
|
|
123
90
|
},
|
|
124
91
|
{
|
|
125
|
-
name: '
|
|
126
|
-
value: 'pz-
|
|
92
|
+
name: 'Click & Collect',
|
|
93
|
+
value: 'pz-click-collect'
|
|
127
94
|
},
|
|
128
95
|
{
|
|
129
96
|
name: 'Checkout Gift Pack',
|
|
130
97
|
value: 'pz-checkout-gift-pack'
|
|
131
98
|
},
|
|
132
99
|
{
|
|
133
|
-
name: 'Click
|
|
134
|
-
value: 'pz-click-
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: 'Credit Payment',
|
|
138
|
-
value: 'pz-credit-payment'
|
|
100
|
+
name: 'One Click Checkout',
|
|
101
|
+
value: 'pz-one-click-checkout'
|
|
139
102
|
},
|
|
140
103
|
{
|
|
141
104
|
name: 'Garanti Pay',
|
|
142
105
|
value: 'pz-gpay'
|
|
143
106
|
},
|
|
144
107
|
{
|
|
145
|
-
name: '
|
|
146
|
-
value: 'pz-
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
name: 'Multi Basket',
|
|
150
|
-
value: 'pz-multi-basket'
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
name: 'One Click Checkout',
|
|
154
|
-
value: 'pz-one-click-checkout'
|
|
108
|
+
name: 'Pay On Delivery',
|
|
109
|
+
value: 'pz-pay-on-delivery'
|
|
155
110
|
},
|
|
156
111
|
{
|
|
157
112
|
name: 'Otp',
|
|
158
113
|
value: 'pz-otp'
|
|
159
114
|
},
|
|
160
115
|
{
|
|
161
|
-
name: '
|
|
162
|
-
value: 'pz-
|
|
116
|
+
name: 'BKM Express',
|
|
117
|
+
value: 'pz-bkm'
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'Credit Payment',
|
|
121
|
+
value: 'pz-credit-payment'
|
|
163
122
|
},
|
|
164
123
|
{
|
|
165
|
-
name: '
|
|
166
|
-
value: 'pz-
|
|
124
|
+
name: 'Multi Basket',
|
|
125
|
+
value: 'pz-multi-basket'
|
|
167
126
|
},
|
|
168
127
|
{
|
|
169
128
|
name: 'Tabby Payment Extension',
|
package/package.json
CHANGED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Skeleton, SkeletonWrapper } from 'components';
|
|
2
|
-
|
|
3
|
-
export default function Loading() {
|
|
4
|
-
return (
|
|
5
|
-
<div className="container mx-auto">
|
|
6
|
-
<div className="max-w-5xl mx-auto my-5 px-7">
|
|
7
|
-
<SkeletonWrapper className="md:mb-7">
|
|
8
|
-
<Skeleton className="w-[17.25rem] h-4 lg:w-64" />
|
|
9
|
-
</SkeletonWrapper>
|
|
10
|
-
</div>
|
|
11
|
-
<div className="grid max-w-5xl grid-cols-2 lg:gap-8 mx-auto px-7">
|
|
12
|
-
<div className="col-span-2 mb-7 md:mb-0 lg:col-span-1">
|
|
13
|
-
<div className="flex gap-1">
|
|
14
|
-
<SkeletonWrapper className="hidden md:block md:mb-7">
|
|
15
|
-
{Array(5)
|
|
16
|
-
.fill(null)
|
|
17
|
-
.map((_, index) => (
|
|
18
|
-
<Skeleton key={index} className="w-20 h-24 mb-2" />
|
|
19
|
-
))}
|
|
20
|
-
</SkeletonWrapper>
|
|
21
|
-
|
|
22
|
-
<div className="flex-1">
|
|
23
|
-
<SkeletonWrapper className="md:mb-7">
|
|
24
|
-
<Skeleton className="w-full h-[30.375rem] md:h-[36.375rem]" />
|
|
25
|
-
</SkeletonWrapper>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</div>
|
|
29
|
-
<div className="flex flex-col items-center col-span-2 lg:col-span-1">
|
|
30
|
-
<div className="w-full">
|
|
31
|
-
<SkeletonWrapper className="w-full md:mb-7 flex justify-center items-center">
|
|
32
|
-
<Skeleton className="w-96 h-16 mb-9" />
|
|
33
|
-
<Skeleton className="hidden w-36 h-14 mb-9 md:block" />
|
|
34
|
-
|
|
35
|
-
<div className="flex flex-col justify-center items-center mb-9">
|
|
36
|
-
<Skeleton className="w-36 h-4 mb-2" />
|
|
37
|
-
<div className="flex items-center gap-2">
|
|
38
|
-
{Array(3)
|
|
39
|
-
.fill(null)
|
|
40
|
-
.map((_, index) => (
|
|
41
|
-
<Skeleton key={index} className="w-24 h-10" />
|
|
42
|
-
))}
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
|
|
46
|
-
<div className="flex flex-col justify-center items-center mb-4">
|
|
47
|
-
<Skeleton className="w-36 h-4 mb-2" />
|
|
48
|
-
<div className="flex items-center gap-2">
|
|
49
|
-
{Array(5)
|
|
50
|
-
.fill(null)
|
|
51
|
-
.map((_, index) => (
|
|
52
|
-
<Skeleton key={index} className="w-11 h-11" />
|
|
53
|
-
))}
|
|
54
|
-
</div>
|
|
55
|
-
</div>
|
|
56
|
-
|
|
57
|
-
<Skeleton className="hidden w-full h-14 mb-6 md:block" />
|
|
58
|
-
<Skeleton className="w-40 h-10 mb-9 md:w-72" />
|
|
59
|
-
<Skeleton className="w-24 h-10 mb-7" />
|
|
60
|
-
<Skeleton className="w-full h-36" />
|
|
61
|
-
</SkeletonWrapper>
|
|
62
|
-
</div>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@akinon/next/api/image-proxy';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@akinon/next/api/similar-product-list';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@akinon/next/api/similar-products';
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { useAddProductToBasket } from './index';
|
|
3
|
-
import { pushAddToCart } from '@theme/utils/gtm';
|
|
4
|
-
import { validateVariantSelection } from '../utils/variant-validation';
|
|
5
|
-
import { VariantType } from '@akinon/next/types';
|
|
6
|
-
|
|
7
|
-
interface Product {
|
|
8
|
-
pk: number;
|
|
9
|
-
[key: string]: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface UseProductCartProps {
|
|
13
|
-
product: Product;
|
|
14
|
-
variants: VariantType[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
interface AddToCartError {
|
|
18
|
-
data?: {
|
|
19
|
-
non_field_errors?: string[];
|
|
20
|
-
[key: string]: string[];
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export const useProductCart = ({ product, variants }: UseProductCartProps) => {
|
|
25
|
-
const [productError, setProductError] = useState<React.ReactNode | null>(null);
|
|
26
|
-
const [addProduct, { isLoading: isAddToCartLoading }] = useAddProductToBasket();
|
|
27
|
-
|
|
28
|
-
const formatError = (error: AddToCartError) => {
|
|
29
|
-
if (error?.data?.non_field_errors) {
|
|
30
|
-
return error.data.non_field_errors;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (error?.data) {
|
|
34
|
-
return Object.keys(error.data).map(
|
|
35
|
-
(key) => `${key}: ${error.data[key].join(', ')}`
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return 'An error occurred';
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const addProductToCart = async () => {
|
|
43
|
-
const validation = validateVariantSelection(variants);
|
|
44
|
-
|
|
45
|
-
if (!validation.isValid) {
|
|
46
|
-
setProductError(validation.errorMessage);
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
await addProduct({
|
|
52
|
-
product: product.pk,
|
|
53
|
-
quantity: 1,
|
|
54
|
-
attributes: {}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
pushAddToCart(product);
|
|
58
|
-
setProductError(null);
|
|
59
|
-
return true;
|
|
60
|
-
} catch (error) {
|
|
61
|
-
const formattedError = formatError(error as AddToCartError);
|
|
62
|
-
setProductError(formattedError);
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const clearProductError = () => {
|
|
68
|
-
setProductError(null);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
addProductToCart,
|
|
73
|
-
productError,
|
|
74
|
-
clearProductError,
|
|
75
|
-
isAddToCartLoading
|
|
76
|
-
};
|
|
77
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { useAddStockAlertMutation } from '@akinon/next/data/client/wishlist';
|
|
3
|
-
import { Trans } from '@akinon/next/components/trans';
|
|
4
|
-
import { useLocalization } from '@akinon/next/hooks';
|
|
5
|
-
|
|
6
|
-
interface UseStockAlertProps {
|
|
7
|
-
productPk: number;
|
|
8
|
-
userEmail?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const useStockAlert = ({ productPk, userEmail }: UseStockAlertProps) => {
|
|
12
|
-
const { t } = useLocalization();
|
|
13
|
-
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
14
|
-
const [stockAlertResponseMessage, setStockAlertResponseMessage] = useState<React.ReactNode | null>(null);
|
|
15
|
-
const [productError, setProductError] = useState<React.ReactNode | null>(null);
|
|
16
|
-
|
|
17
|
-
const [addStockAlert, { isLoading: isAddToStockAlertLoading }] = useAddStockAlertMutation();
|
|
18
|
-
|
|
19
|
-
const handleSuccess = () => {
|
|
20
|
-
setStockAlertResponseMessage(React.createElement(
|
|
21
|
-
Trans,
|
|
22
|
-
{
|
|
23
|
-
i18nKey: "product.stock_alert.success_description",
|
|
24
|
-
components: {
|
|
25
|
-
Email: React.createElement('span', {}, userEmail)
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
));
|
|
29
|
-
setIsModalOpen(true);
|
|
30
|
-
setProductError(null);
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const handleError = (err: any) => {
|
|
34
|
-
if (err.status !== 401) {
|
|
35
|
-
setStockAlertResponseMessage(
|
|
36
|
-
t('product.stock_alert.error_description').toString()
|
|
37
|
-
);
|
|
38
|
-
setIsModalOpen(true);
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const addProductToStockAlertList = async () => {
|
|
43
|
-
try {
|
|
44
|
-
await addStockAlert({
|
|
45
|
-
productPk,
|
|
46
|
-
email: userEmail
|
|
47
|
-
})
|
|
48
|
-
.unwrap()
|
|
49
|
-
.then(handleSuccess)
|
|
50
|
-
.catch(handleError);
|
|
51
|
-
} catch (error: any) {
|
|
52
|
-
setProductError(error?.data?.non_field_errors || null);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const closeModal = () => {
|
|
57
|
-
setIsModalOpen(false);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const clearError = () => {
|
|
61
|
-
setProductError(null);
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
addProductToStockAlertList,
|
|
66
|
-
isModalOpen,
|
|
67
|
-
setIsModalOpen,
|
|
68
|
-
stockAlertResponseMessage,
|
|
69
|
-
productError,
|
|
70
|
-
isAddToStockAlertLoading,
|
|
71
|
-
closeModal,
|
|
72
|
-
clearError
|
|
73
|
-
};
|
|
74
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Trans } from '@akinon/next/components/trans';
|
|
3
|
-
import { VariantType } from '@akinon/next/types';
|
|
4
|
-
|
|
5
|
-
export const isVariantSelectionComplete = (variants: VariantType[]): boolean => {
|
|
6
|
-
return variants?.every((variant) =>
|
|
7
|
-
variant?.options.some((opt) => opt.is_selected)
|
|
8
|
-
);
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const getUnselectedVariant = (variants: VariantType[]): VariantType | undefined => {
|
|
12
|
-
return variants.find((variant) =>
|
|
13
|
-
variant.options.every((opt) => !opt.is_selected)
|
|
14
|
-
);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const createVariantErrorMessage = (unselectedVariant: VariantType) => {
|
|
18
|
-
const TransComponent = Trans as any;
|
|
19
|
-
return React.createElement(
|
|
20
|
-
TransComponent,
|
|
21
|
-
{
|
|
22
|
-
i18nKey: "product.please_select_variant",
|
|
23
|
-
components: {
|
|
24
|
-
VariantName: React.createElement('span', {}, unselectedVariant.attribute_name)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const validateVariantSelection = (variants: VariantType[]) => {
|
|
31
|
-
const unselectedVariant = getUnselectedVariant(variants);
|
|
32
|
-
|
|
33
|
-
if (unselectedVariant) {
|
|
34
|
-
return {
|
|
35
|
-
isValid: false,
|
|
36
|
-
errorMessage: createVariantErrorMessage(unselectedVariant)
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return { isValid: true, errorMessage: null };
|
|
41
|
-
};
|
|
@@ -1,106 +0,0 @@
|
|
|
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
|
-
}
|