@akinon/pz-b2b 1.62.0 → 1.63.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 +6 -0
- package/README.md +23 -5
- package/package.json +1 -1
- package/src/basket-b2b/index.tsx +77 -11
- package/src/views/basket-b2b/index.ts +1 -0
- package/src/views/basket-b2b/upload-modal.tsx +106 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -102,6 +102,15 @@ Add the translation inside the basket object. Apply this for every language
|
|
|
102
102
|
"add_to_favorites_button": "ADD TO FAVORITES",
|
|
103
103
|
"delete_product_button": "delete product"
|
|
104
104
|
},
|
|
105
|
+
"upload_file_modal": {
|
|
106
|
+
"select_file": "Select File",
|
|
107
|
+
"upload": "Upload",
|
|
108
|
+
"no_file_selected": "No file selected",
|
|
109
|
+
"error": {
|
|
110
|
+
"upload_failed": "An error occurred while uploading the file",
|
|
111
|
+
"no_file_selected": "Please select a file before uploading."
|
|
112
|
+
}
|
|
113
|
+
},
|
|
105
114
|
"empty": {
|
|
106
115
|
"title": "Your cart is empty, would you like to continue with your saved carts?",
|
|
107
116
|
"button": "SELECT CART",
|
|
@@ -141,6 +150,15 @@ Add the translation inside the basket object. Apply this for every language
|
|
|
141
150
|
"add_to_favorites_button": "FAVORİLERE EKLE",
|
|
142
151
|
"delete_product_button": "ürünü sil"
|
|
143
152
|
},
|
|
153
|
+
"upload_file_modal": {
|
|
154
|
+
"select_file": "Dosya Seç",
|
|
155
|
+
"upload": "Yükle",
|
|
156
|
+
"no_file_selected": "Dosya seçilmedi",
|
|
157
|
+
"error": {
|
|
158
|
+
"upload_failed": "Dosya yüklenirken bir hata oluştu",
|
|
159
|
+
"no_file_selected": "Lütfen yüklemeden önce bir dosya seçin"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
144
162
|
"empty": {
|
|
145
163
|
"title": "Sepetiniz boş, kaydettiğiniz sepetlerle devam etmek ister misiniz?",
|
|
146
164
|
"button": "SEPETİ SEÇ",
|
|
@@ -189,7 +207,7 @@ rewrites: [
|
|
|
189
207
|
Add plugin name
|
|
190
208
|
|
|
191
209
|
```javascript
|
|
192
|
-
module.exports = [
|
|
210
|
+
module.exports = ['...', 'pz-b2b'];
|
|
193
211
|
```
|
|
194
212
|
|
|
195
213
|
##### File Path: src/views/product/product-info.tsx
|
|
@@ -197,7 +215,7 @@ module.exports = ["...", "pz-b2b"];
|
|
|
197
215
|
Add imports
|
|
198
216
|
|
|
199
217
|
```javascript
|
|
200
|
-
import { useB2b, StoreModal } from
|
|
218
|
+
import { useB2b, StoreModal } from '@akinon/pz-b2b';
|
|
201
219
|
```
|
|
202
220
|
|
|
203
221
|
Add useB2b hook
|
|
@@ -208,14 +226,14 @@ const {
|
|
|
208
226
|
setOpenSelectStoreModal,
|
|
209
227
|
divisions,
|
|
210
228
|
divisionLoading,
|
|
211
|
-
B2bButton
|
|
229
|
+
B2bButton
|
|
212
230
|
} = useB2b();
|
|
213
231
|
```
|
|
214
232
|
|
|
215
233
|
Add open modal button
|
|
216
234
|
|
|
217
235
|
```javascript
|
|
218
|
-
<B2bButton buttonText={t(
|
|
236
|
+
<B2bButton buttonText={t('product.add_to_cart')} />
|
|
219
237
|
```
|
|
220
238
|
|
|
221
239
|
Add the end in the return
|
|
@@ -229,6 +247,6 @@ Add the end in the return
|
|
|
229
247
|
open={openSelectStoreModal}
|
|
230
248
|
setOpen={setOpenSelectStoreModal}
|
|
231
249
|
/>
|
|
232
|
-
)
|
|
250
|
+
);
|
|
233
251
|
}
|
|
234
252
|
```
|
package/package.json
CHANGED
package/src/basket-b2b/index.tsx
CHANGED
|
@@ -7,18 +7,22 @@ import {
|
|
|
7
7
|
Trans,
|
|
8
8
|
Price,
|
|
9
9
|
Icon,
|
|
10
|
-
Link
|
|
10
|
+
Link,
|
|
11
|
+
Button
|
|
11
12
|
} from '@akinon/next/components';
|
|
12
13
|
import {
|
|
13
14
|
useGetBasketB2bQuery,
|
|
14
15
|
useGetDraftsQuery,
|
|
15
|
-
useLoadBasketMutation
|
|
16
|
+
useLoadBasketMutation,
|
|
17
|
+
useGetBasketStatusMutation,
|
|
18
|
+
useExportBasketMutation
|
|
16
19
|
} from '@akinon/next/data/client/b2b';
|
|
17
20
|
import {
|
|
18
21
|
BasketItem,
|
|
19
22
|
RequestQuoteModal,
|
|
20
23
|
RemoveProductModal,
|
|
21
|
-
SaveCartModal
|
|
24
|
+
SaveCartModal,
|
|
25
|
+
UploadModal
|
|
22
26
|
} from '../views/basket-b2b';
|
|
23
27
|
|
|
24
28
|
interface BasketB2bTranslationsProps {
|
|
@@ -66,11 +70,14 @@ interface BasketB2bProps {
|
|
|
66
70
|
|
|
67
71
|
export function BasketB2b({ translations }: BasketB2bProps) {
|
|
68
72
|
const { data: basket, isLoading, isSuccess } = useGetBasketB2bQuery();
|
|
73
|
+
const [getBasketStatus] = useGetBasketStatusMutation();
|
|
74
|
+
const [exportBasket] = useExportBasketMutation();
|
|
69
75
|
const [loadBasket] = useLoadBasketMutation();
|
|
70
76
|
const { data: dataDraft } = useGetDraftsQuery();
|
|
71
77
|
const [open, setOpen] = useState(false);
|
|
72
78
|
const [openRequestQuote, setRequestQuote] = useState(false);
|
|
73
79
|
const [openRemoveProduct, setRemoveProduct] = useState(false);
|
|
80
|
+
const [openUploadBasket, setUploadBasket] = useState(false);
|
|
74
81
|
const [productToBeDeleted, setProductToBeDeleted] = useState(null);
|
|
75
82
|
const [selectedDraft, setSelectedDraft] = useState(null);
|
|
76
83
|
|
|
@@ -129,6 +136,42 @@ export function BasketB2b({ translations }: BasketB2bProps) {
|
|
|
129
136
|
|
|
130
137
|
loadBasket(selectedDraft);
|
|
131
138
|
};
|
|
139
|
+
const handleDownload = async () => {
|
|
140
|
+
const fieldsArray = [
|
|
141
|
+
'product__sku',
|
|
142
|
+
'quantity',
|
|
143
|
+
'division__erp_code',
|
|
144
|
+
'division__name',
|
|
145
|
+
'price',
|
|
146
|
+
'variants__Renk'
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
const queryString = new URLSearchParams(
|
|
150
|
+
fieldsArray.map((queryName) => ['_fields', queryName])
|
|
151
|
+
).toString();
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const data = await exportBasket(queryString).unwrap();
|
|
155
|
+
await handleDownloadStatus(data.cache_key);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
console.error('Error during download process:', error);
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const handleDownloadStatus = async (cacheKey) => {
|
|
162
|
+
try {
|
|
163
|
+
const data = await getBasketStatus(cacheKey).unwrap();
|
|
164
|
+
if (data.status === 'completed') {
|
|
165
|
+
window.location.href = data.url;
|
|
166
|
+
} else if (data.status === 'waiting') {
|
|
167
|
+
setTimeout(() => handleDownloadStatus(cacheKey), 2000);
|
|
168
|
+
} else {
|
|
169
|
+
console.warn(`Unhandled status: ${data.status}`);
|
|
170
|
+
}
|
|
171
|
+
} catch (error) {
|
|
172
|
+
console.error('Error fetching basket data:', error);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
132
175
|
|
|
133
176
|
useEffect(() => {
|
|
134
177
|
if (isSuccess) {
|
|
@@ -156,19 +199,36 @@ export function BasketB2b({ translations }: BasketB2bProps) {
|
|
|
156
199
|
<h2 className="text-xl lg:text-2xl font-light">
|
|
157
200
|
{_translations.my_cart}
|
|
158
201
|
</h2>
|
|
159
|
-
|
|
160
202
|
<Link href="/" className="text-xs hover:text-secondary-500">
|
|
161
203
|
{_translations.back_to_shopping}
|
|
162
204
|
</Link>
|
|
163
205
|
</div>
|
|
164
206
|
|
|
165
|
-
<div className="px-5 py-4 border border-b-0 border-gray-200
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
207
|
+
<div className="flex justify-between items-center px-5 py-4 border border-b-0 border-gray-200">
|
|
208
|
+
<div className=" text-xs text-[#363636]">
|
|
209
|
+
<Trans
|
|
210
|
+
i18nKey={_translations.table.basket_qty}
|
|
211
|
+
components={{
|
|
212
|
+
Qty: <span>{basket.total_quantity}</span>
|
|
213
|
+
}}
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
216
|
+
<div className="flex items-center gap-2">
|
|
217
|
+
<Button
|
|
218
|
+
className="flex flex-col items-center justify-center"
|
|
219
|
+
onClick={() => setUploadBasket(true)}
|
|
220
|
+
>
|
|
221
|
+
<span>XLS</span>
|
|
222
|
+
<Icon name="chevron-up" size={12} />
|
|
223
|
+
</Button>
|
|
224
|
+
<Button
|
|
225
|
+
className="flex flex-col items-center justify-center"
|
|
226
|
+
onClick={handleDownload}
|
|
227
|
+
>
|
|
228
|
+
<span>XLS</span>
|
|
229
|
+
<Icon name="chevron-down" size={12} />
|
|
230
|
+
</Button>
|
|
231
|
+
</div>
|
|
172
232
|
</div>
|
|
173
233
|
|
|
174
234
|
<div className="w-full overflow-x-auto">
|
|
@@ -322,6 +382,12 @@ export function BasketB2b({ translations }: BasketB2bProps) {
|
|
|
322
382
|
_translations.remove_product_modal.delete_product_button
|
|
323
383
|
}
|
|
324
384
|
/>
|
|
385
|
+
|
|
386
|
+
<UploadModal
|
|
387
|
+
setOpen={setUploadBasket}
|
|
388
|
+
open={openUploadBasket}
|
|
389
|
+
modalTitle="File Upload"
|
|
390
|
+
/>
|
|
325
391
|
</div>
|
|
326
392
|
</>
|
|
327
393
|
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useUploadFileMutation } from '@akinon/next/data/client/b2b';
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
|
+
import { Button } from '@akinon/next/components';
|
|
6
|
+
import { useLocalization } from '@akinon/next/hooks';
|
|
7
|
+
|
|
8
|
+
export const UploadModal = ({
|
|
9
|
+
open,
|
|
10
|
+
setOpen,
|
|
11
|
+
modalTitle
|
|
12
|
+
}: {
|
|
13
|
+
open: boolean;
|
|
14
|
+
setOpen: (open: boolean) => void;
|
|
15
|
+
modalTitle: string;
|
|
16
|
+
}) => {
|
|
17
|
+
const { t } = useLocalization();
|
|
18
|
+
const [file, setFile] = useState<File | null>(null);
|
|
19
|
+
const [uploadFile, { isLoading }] = useUploadFileMutation();
|
|
20
|
+
const [error, setError] = useState<string | null>(null);
|
|
21
|
+
|
|
22
|
+
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
23
|
+
setFile(e.target.files?.[0] || null);
|
|
24
|
+
setError(null);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
|
|
30
|
+
if (!file) {
|
|
31
|
+
setError(t('basket.b2b.upload_file_modal.error.no_file_selected'));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const formData = new FormData();
|
|
36
|
+
formData.append('filename', file);
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
await uploadFile(formData).unwrap();
|
|
40
|
+
setOpen(false);
|
|
41
|
+
setFile(null);
|
|
42
|
+
setError(null);
|
|
43
|
+
} catch (uploadError) {
|
|
44
|
+
setError(t('basket.b2b.upload_file_modal.error.upload_failed'));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
if (!open) return null;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div className="before:w-full before:h-screen before:content-[''] before:bg-black/60 before:z-40 before:fixed before:inset-0">
|
|
52
|
+
<div className="w-11/12 max-w-[344px] md:w-[370px] left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50 fixed bg-white">
|
|
53
|
+
<header className="relative border-b border-[#d5dadb]">
|
|
54
|
+
<h3 className="text-left px-[30px] py-4 font-medium text-lg">
|
|
55
|
+
{modalTitle}
|
|
56
|
+
</h3>
|
|
57
|
+
<button
|
|
58
|
+
className="absolute right-[30px] top-5"
|
|
59
|
+
onClick={() => setOpen(false)}
|
|
60
|
+
>
|
|
61
|
+
<i className="pz-icon-close"></i>
|
|
62
|
+
</button>
|
|
63
|
+
</header>
|
|
64
|
+
<div className="p-[30px]">
|
|
65
|
+
<form onSubmit={handleSubmit}>
|
|
66
|
+
<div className="relative flex flex-col justify-center items-center mb-4">
|
|
67
|
+
<input
|
|
68
|
+
type="file"
|
|
69
|
+
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
|
70
|
+
onChange={handleFileChange}
|
|
71
|
+
className="opacity-0 w-full absolute left-0 top-0 h-full text-[0px] cursor-pointer"
|
|
72
|
+
/>
|
|
73
|
+
<Button className="pointer-events-none h-9 text-white border rounded mb-1">
|
|
74
|
+
{t('basket.b2b.upload_file_modal.select_file')}
|
|
75
|
+
</Button>
|
|
76
|
+
|
|
77
|
+
<p className="text-xs text-[#3e3e3e]">
|
|
78
|
+
{file
|
|
79
|
+
? file.name
|
|
80
|
+
: t('basket.b2b.upload_file_modal.no_file_selected')}
|
|
81
|
+
</p>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
{error && (
|
|
85
|
+
<p className="text-xs text-center text-error mb-4">{error}</p>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
<Button
|
|
89
|
+
type="submit"
|
|
90
|
+
className="h-8 bg-black text-white font-medium text-sm w-full"
|
|
91
|
+
disabled={isLoading}
|
|
92
|
+
>
|
|
93
|
+
{isLoading ? (
|
|
94
|
+
<div className="w-full h-full flex justify-center items-center">
|
|
95
|
+
<div className="w-4 h-4 border-2 border-gray-600 border-t-transparent rounded-full animate-spin" />
|
|
96
|
+
</div>
|
|
97
|
+
) : (
|
|
98
|
+
t('basket.b2b.upload_file_modal.upload')
|
|
99
|
+
)}
|
|
100
|
+
</Button>
|
|
101
|
+
</form>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
);
|
|
106
|
+
};
|