@lodashventure/medusa-parcel-shipping 0.4.7 → 0.4.8
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/.medusa/server/src/admin/index.js +955 -955
- package/.medusa/server/src/admin/index.mjs +957 -957
- package/package.json +1 -1
|
@@ -218,116 +218,55 @@ const OrderShippingQuoteWidget = ({ data }) => {
|
|
|
218
218
|
adminSdk.defineWidgetConfig({
|
|
219
219
|
zone: "order.details.after"
|
|
220
220
|
});
|
|
221
|
-
const
|
|
222
|
-
"กรุงเทพมหานคร",
|
|
223
|
-
"กระบี่",
|
|
224
|
-
"กาญจนบุรี",
|
|
225
|
-
"กาฬสินธุ์",
|
|
226
|
-
"กำแพงเพชร",
|
|
227
|
-
"ขอนแก่น",
|
|
228
|
-
"จันทบุรี",
|
|
229
|
-
"ฉะเชิงเทรา",
|
|
230
|
-
"ชลบุรี",
|
|
231
|
-
"ชัยนาท",
|
|
232
|
-
"ชัยภูมิ",
|
|
233
|
-
"ชุมพร",
|
|
234
|
-
"เชียงราย",
|
|
235
|
-
"เชียงใหม่",
|
|
236
|
-
"ตรัง",
|
|
237
|
-
"ตราด",
|
|
238
|
-
"ตาก",
|
|
239
|
-
"นครนายก",
|
|
240
|
-
"นครปฐม",
|
|
241
|
-
"นครพนม",
|
|
242
|
-
"นครราชสีมา",
|
|
243
|
-
"นครศรีธรรมราช",
|
|
244
|
-
"นครสวรรค์",
|
|
245
|
-
"นนทบุรี",
|
|
246
|
-
"นราธิวาส",
|
|
247
|
-
"น่าน",
|
|
248
|
-
"บึงกาฬ",
|
|
249
|
-
"บุรีรัมย์",
|
|
250
|
-
"ปทุมธานี",
|
|
251
|
-
"ประจวบคีรีขันธ์",
|
|
252
|
-
"ปราจีนบุรี",
|
|
253
|
-
"ปัตตานี",
|
|
254
|
-
"พระนครศรีอยุธยา",
|
|
255
|
-
"พะเยา",
|
|
256
|
-
"พังงา",
|
|
257
|
-
"พัทลุง",
|
|
258
|
-
"พิจิตร",
|
|
259
|
-
"พิษณุโลก",
|
|
260
|
-
"เพชรบุรี",
|
|
261
|
-
"เพชรบูรณ์",
|
|
262
|
-
"แพร่",
|
|
263
|
-
"ภูเก็ต",
|
|
264
|
-
"มหาสารคาม",
|
|
265
|
-
"มุกดาหาร",
|
|
266
|
-
"แม่ฮ่องสอน",
|
|
267
|
-
"ยโสธร",
|
|
268
|
-
"ยะลา",
|
|
269
|
-
"ร้อยเอ็ด",
|
|
270
|
-
"ระนอง",
|
|
271
|
-
"ระยอง",
|
|
272
|
-
"ราชบุรี",
|
|
273
|
-
"ลพบุรี",
|
|
274
|
-
"ลำปาง",
|
|
275
|
-
"ลำพูน",
|
|
276
|
-
"เลย",
|
|
277
|
-
"ศรีสะเกษ",
|
|
278
|
-
"สกลนคร",
|
|
279
|
-
"สงขลา",
|
|
280
|
-
"สตูล",
|
|
281
|
-
"สมุทรปราการ",
|
|
282
|
-
"สมุทรสงคราม",
|
|
283
|
-
"สมุทรสาคร",
|
|
284
|
-
"สระแก้ว",
|
|
285
|
-
"สระบุรี",
|
|
286
|
-
"สิงห์บุรี",
|
|
287
|
-
"สุโขทัย",
|
|
288
|
-
"สุพรรณบุรี",
|
|
289
|
-
"สุราษฎร์ธานี",
|
|
290
|
-
"สุรินทร์",
|
|
291
|
-
"หนองคาย",
|
|
292
|
-
"หนองบัวลำภู",
|
|
293
|
-
"อ่างทอง",
|
|
294
|
-
"อำนาจเจริญ",
|
|
295
|
-
"อุดรธานี",
|
|
296
|
-
"อุตรดิตถ์",
|
|
297
|
-
"อุทัยธานี",
|
|
298
|
-
"อุบลราชธานี"
|
|
299
|
-
];
|
|
300
|
-
const ServiceAreaModal = ({ area, onClose }) => {
|
|
221
|
+
const ParcelBoxModal = ({ box, onClose }) => {
|
|
301
222
|
const [formData, setFormData] = react.useState({
|
|
302
|
-
|
|
303
|
-
|
|
223
|
+
name: "",
|
|
224
|
+
width_cm: "",
|
|
225
|
+
length_cm: "",
|
|
226
|
+
height_cm: "",
|
|
227
|
+
max_weight_kg: "",
|
|
228
|
+
price_thb: "",
|
|
304
229
|
active: true
|
|
305
230
|
});
|
|
306
231
|
const [isSaving, setIsSaving] = react.useState(false);
|
|
307
232
|
react.useEffect(() => {
|
|
308
|
-
if (
|
|
233
|
+
if (box) {
|
|
309
234
|
setFormData({
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
235
|
+
name: box.name,
|
|
236
|
+
width_cm: box.width_cm.toString(),
|
|
237
|
+
length_cm: box.length_cm.toString(),
|
|
238
|
+
height_cm: box.height_cm.toString(),
|
|
239
|
+
max_weight_kg: box.max_weight_kg.toString(),
|
|
240
|
+
price_thb: box.price_thb.toString(),
|
|
241
|
+
active: box.active
|
|
313
242
|
});
|
|
314
243
|
}
|
|
315
|
-
}, [
|
|
244
|
+
}, [box]);
|
|
316
245
|
const handleSubmit = async (e) => {
|
|
317
246
|
e.preventDefault();
|
|
318
247
|
const errors = [];
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
errors.push("กรุณากรอกค่า");
|
|
248
|
+
if (!formData.name.trim()) {
|
|
249
|
+
errors.push("กรุณากรอกชื่อกล่อง");
|
|
322
250
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
251
|
+
const width = parseFloat(formData.width_cm);
|
|
252
|
+
const length = parseFloat(formData.length_cm);
|
|
253
|
+
const height = parseFloat(formData.height_cm);
|
|
254
|
+
const maxWeight = parseFloat(formData.max_weight_kg);
|
|
255
|
+
const price = parseFloat(formData.price_thb);
|
|
256
|
+
if (isNaN(width) || width <= 0) {
|
|
257
|
+
errors.push("ความกว้างต้องเป็นตัวเลขมากกว่า 0");
|
|
258
|
+
}
|
|
259
|
+
if (isNaN(length) || length <= 0) {
|
|
260
|
+
errors.push("ความยาวต้องเป็นตัวเลขมากกว่า 0");
|
|
261
|
+
}
|
|
262
|
+
if (isNaN(height) || height <= 0) {
|
|
263
|
+
errors.push("ความสูงต้องเป็นตัวเลขมากกว่า 0");
|
|
264
|
+
}
|
|
265
|
+
if (isNaN(maxWeight) || maxWeight <= 0) {
|
|
266
|
+
errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
|
|
267
|
+
}
|
|
268
|
+
if (isNaN(price) || price < 0) {
|
|
269
|
+
errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
|
|
331
270
|
}
|
|
332
271
|
if (errors.length > 0) {
|
|
333
272
|
ui.toast.error("ข้อมูลไม่ถูกต้อง", {
|
|
@@ -338,12 +277,16 @@ const ServiceAreaModal = ({ area, onClose }) => {
|
|
|
338
277
|
setIsSaving(true);
|
|
339
278
|
try {
|
|
340
279
|
const payload = {
|
|
341
|
-
|
|
342
|
-
|
|
280
|
+
name: formData.name.trim(),
|
|
281
|
+
width_cm: width,
|
|
282
|
+
length_cm: length,
|
|
283
|
+
height_cm: height,
|
|
284
|
+
max_weight_kg: maxWeight,
|
|
285
|
+
price_thb: price,
|
|
343
286
|
active: formData.active
|
|
344
287
|
};
|
|
345
|
-
const url =
|
|
346
|
-
const method =
|
|
288
|
+
const url = box ? `/admin/boxes/${box.id}` : "/admin/boxes";
|
|
289
|
+
const method = box ? "PUT" : "POST";
|
|
347
290
|
const response = await fetch(url, {
|
|
348
291
|
method,
|
|
349
292
|
headers: { "Content-Type": "application/json" },
|
|
@@ -352,7 +295,7 @@ const ServiceAreaModal = ({ area, onClose }) => {
|
|
|
352
295
|
});
|
|
353
296
|
if (response.ok) {
|
|
354
297
|
ui.toast.success("สำเร็จ", {
|
|
355
|
-
description:
|
|
298
|
+
description: box ? "แก้ไขกล่องพัสดุแล้ว" : "สร้างกล่องพัสดุใหม่แล้ว"
|
|
356
299
|
});
|
|
357
300
|
onClose();
|
|
358
301
|
} else {
|
|
@@ -368,53 +311,97 @@ const ServiceAreaModal = ({ area, onClose }) => {
|
|
|
368
311
|
}
|
|
369
312
|
};
|
|
370
313
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
371
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children:
|
|
314
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: box ? "แก้ไขกล่องพัสดุ" : "สร้างกล่องพัสดุใหม่" }) }),
|
|
372
315
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
|
|
373
316
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
374
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
375
|
-
/* @__PURE__ */ jsxRuntime.
|
|
376
|
-
ui.
|
|
317
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "name", children: "ชื่อกล่อง *" }),
|
|
318
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
319
|
+
ui.Input,
|
|
377
320
|
{
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Content, { children: [
|
|
384
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "PROVINCE", children: "จังหวัด" }),
|
|
385
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "POSTCODE_PREFIX", children: "รหัสไปรษณีย์" })
|
|
386
|
-
] })
|
|
387
|
-
]
|
|
321
|
+
id: "name",
|
|
322
|
+
value: formData.name,
|
|
323
|
+
onChange: (e) => setFormData({ ...formData, name: e.target.value }),
|
|
324
|
+
placeholder: "เช่น กล่อง S, กล่อง M",
|
|
325
|
+
required: true
|
|
388
326
|
}
|
|
389
327
|
)
|
|
390
328
|
] }),
|
|
329
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-x-4", children: [
|
|
330
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
331
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "width", children: "ความกว้าง (cm) *" }),
|
|
332
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
333
|
+
ui.Input,
|
|
334
|
+
{
|
|
335
|
+
id: "width",
|
|
336
|
+
type: "number",
|
|
337
|
+
step: "0.1",
|
|
338
|
+
value: formData.width_cm,
|
|
339
|
+
onChange: (e) => setFormData({ ...formData, width_cm: e.target.value }),
|
|
340
|
+
placeholder: "20",
|
|
341
|
+
required: true
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
] }),
|
|
345
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
346
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "length", children: "ความยาว (cm) *" }),
|
|
347
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
348
|
+
ui.Input,
|
|
349
|
+
{
|
|
350
|
+
id: "length",
|
|
351
|
+
type: "number",
|
|
352
|
+
step: "0.1",
|
|
353
|
+
value: formData.length_cm,
|
|
354
|
+
onChange: (e) => setFormData({ ...formData, length_cm: e.target.value }),
|
|
355
|
+
placeholder: "30",
|
|
356
|
+
required: true
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
] }),
|
|
360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
361
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "height", children: "ความสูง (cm) *" }),
|
|
362
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
363
|
+
ui.Input,
|
|
364
|
+
{
|
|
365
|
+
id: "height",
|
|
366
|
+
type: "number",
|
|
367
|
+
step: "0.1",
|
|
368
|
+
value: formData.height_cm,
|
|
369
|
+
onChange: (e) => setFormData({ ...formData, height_cm: e.target.value }),
|
|
370
|
+
placeholder: "15",
|
|
371
|
+
required: true
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
] })
|
|
375
|
+
] }),
|
|
391
376
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
392
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
393
|
-
|
|
394
|
-
ui.
|
|
377
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
|
|
378
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
379
|
+
ui.Input,
|
|
395
380
|
{
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
381
|
+
id: "maxWeight",
|
|
382
|
+
type: "number",
|
|
383
|
+
step: "0.1",
|
|
384
|
+
value: formData.max_weight_kg,
|
|
385
|
+
onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
|
|
386
|
+
placeholder: "0.5",
|
|
387
|
+
required: true
|
|
403
388
|
}
|
|
404
|
-
)
|
|
389
|
+
)
|
|
390
|
+
] }),
|
|
391
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
392
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
|
|
393
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
405
394
|
ui.Input,
|
|
406
395
|
{
|
|
407
|
-
id: "
|
|
408
|
-
type: "
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
pattern: "\\d{1,5}",
|
|
396
|
+
id: "price",
|
|
397
|
+
type: "number",
|
|
398
|
+
step: "0.01",
|
|
399
|
+
value: formData.price_thb,
|
|
400
|
+
onChange: (e) => setFormData({ ...formData, price_thb: e.target.value }),
|
|
401
|
+
placeholder: "10.00",
|
|
414
402
|
required: true
|
|
415
403
|
}
|
|
416
|
-
)
|
|
417
|
-
formData.kind === "POSTCODE_PREFIX" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: 'ใส่รหัส 1-5 หลักเพื่อครอบคลุมหลายพื้นที่ เช่น "10" = กรุงเทพฯ ทั้งหมด' })
|
|
404
|
+
)
|
|
418
405
|
] }),
|
|
419
406
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
420
407
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -428,81 +415,59 @@ const ServiceAreaModal = ({ area, onClose }) => {
|
|
|
428
415
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
|
|
429
416
|
] }),
|
|
430
417
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
431
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
432
|
-
ui.Button,
|
|
433
|
-
{
|
|
434
|
-
type: "button",
|
|
435
|
-
variant: "secondary",
|
|
436
|
-
onClick: onClose,
|
|
437
|
-
disabled: isSaving,
|
|
438
|
-
children: "ยกเลิก"
|
|
439
|
-
}
|
|
440
|
-
),
|
|
418
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
|
|
441
419
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
|
|
442
420
|
] })
|
|
443
421
|
] }) })
|
|
444
422
|
] }) });
|
|
445
423
|
};
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
{ value: "POSTCODE_PREFIX", label: "รหัสไปรษณีย์" }
|
|
450
|
-
];
|
|
451
|
-
const ServiceAreasTable = () => {
|
|
452
|
-
const [areas, setAreas] = react.useState([]);
|
|
453
|
-
const [filteredAreas, setFilteredAreas] = react.useState([]);
|
|
424
|
+
const ParcelBoxesTable = () => {
|
|
425
|
+
const [boxes, setBoxes] = react.useState([]);
|
|
426
|
+
const [filteredBoxes, setFilteredBoxes] = react.useState([]);
|
|
454
427
|
const [searchTerm, setSearchTerm] = react.useState("");
|
|
455
|
-
const [kindFilter, setKindFilter] = react.useState("ALL");
|
|
456
428
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
457
|
-
const [
|
|
429
|
+
const [editingBox, setEditingBox] = react.useState(null);
|
|
458
430
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
459
|
-
const [
|
|
460
|
-
const [
|
|
431
|
+
const [deleteBoxId, setDeleteBoxId] = react.useState(null);
|
|
432
|
+
const [deleteBoxName, setDeleteBoxName] = react.useState("");
|
|
461
433
|
react.useEffect(() => {
|
|
462
|
-
|
|
434
|
+
fetchBoxes();
|
|
463
435
|
}, []);
|
|
464
436
|
react.useEffect(() => {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
(area) => area.value.toLowerCase().includes(searchTerm.toLowerCase())
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
|
-
setFilteredAreas(filtered);
|
|
475
|
-
}, [searchTerm, kindFilter, areas]);
|
|
476
|
-
const fetchAreas = async () => {
|
|
437
|
+
const filtered = boxes.filter(
|
|
438
|
+
(box) => box.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
439
|
+
);
|
|
440
|
+
setFilteredBoxes(filtered);
|
|
441
|
+
}, [searchTerm, boxes]);
|
|
442
|
+
const fetchBoxes = async () => {
|
|
477
443
|
setIsLoading(true);
|
|
478
444
|
try {
|
|
479
|
-
const response = await fetch("/admin/
|
|
445
|
+
const response = await fetch("/admin/boxes", {
|
|
480
446
|
credentials: "include"
|
|
481
447
|
});
|
|
482
448
|
const data = await response.json();
|
|
483
|
-
|
|
484
|
-
setAreas(data.service_areas || []);
|
|
449
|
+
setBoxes(data.boxes || []);
|
|
485
450
|
} catch (error) {
|
|
486
451
|
ui.toast.error("ข้อผิดพลาด", {
|
|
487
|
-
description: "
|
|
452
|
+
description: "ไม่สามารถโหลดข้อมูลกล่องพัสดุได้"
|
|
488
453
|
});
|
|
489
454
|
} finally {
|
|
490
455
|
setIsLoading(false);
|
|
491
456
|
}
|
|
492
457
|
};
|
|
493
|
-
const handleToggleActive = async (
|
|
458
|
+
const handleToggleActive = async (box) => {
|
|
494
459
|
try {
|
|
495
|
-
const response = await fetch(`/admin/
|
|
460
|
+
const response = await fetch(`/admin/boxes/${box.id}`, {
|
|
496
461
|
method: "PUT",
|
|
497
462
|
headers: { "Content-Type": "application/json" },
|
|
498
463
|
credentials: "include",
|
|
499
|
-
body: JSON.stringify({ ...
|
|
464
|
+
body: JSON.stringify({ ...box, active: !box.active })
|
|
500
465
|
});
|
|
501
466
|
if (response.ok) {
|
|
502
467
|
ui.toast.success("สำเร็จ", {
|
|
503
|
-
description: `${
|
|
468
|
+
description: `${box.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}กล่อง ${box.name} แล้ว`
|
|
504
469
|
});
|
|
505
|
-
|
|
470
|
+
fetchBoxes();
|
|
506
471
|
} else {
|
|
507
472
|
throw new Error("Failed to update");
|
|
508
473
|
}
|
|
@@ -513,87 +478,91 @@ const ServiceAreasTable = () => {
|
|
|
513
478
|
}
|
|
514
479
|
};
|
|
515
480
|
const handleDelete = async () => {
|
|
516
|
-
if (!
|
|
481
|
+
if (!deleteBoxId) return;
|
|
517
482
|
try {
|
|
518
|
-
const response = await fetch(`/admin/
|
|
483
|
+
const response = await fetch(`/admin/boxes/${deleteBoxId}`, {
|
|
519
484
|
method: "DELETE",
|
|
520
485
|
credentials: "include"
|
|
521
486
|
});
|
|
522
487
|
if (response.ok) {
|
|
523
488
|
ui.toast.success("สำเร็จ", {
|
|
524
|
-
description:
|
|
489
|
+
description: `ลบกล่อง ${deleteBoxName} แล้ว`
|
|
525
490
|
});
|
|
526
|
-
|
|
491
|
+
fetchBoxes();
|
|
527
492
|
} else {
|
|
528
493
|
throw new Error("Failed to delete");
|
|
529
494
|
}
|
|
530
495
|
} catch (error) {
|
|
531
496
|
ui.toast.error("ข้อผิดพลาด", {
|
|
532
|
-
description: "
|
|
497
|
+
description: "ไม่สามารถลบกล่องได้"
|
|
533
498
|
});
|
|
534
499
|
} finally {
|
|
535
|
-
|
|
536
|
-
|
|
500
|
+
setDeleteBoxId(null);
|
|
501
|
+
setDeleteBoxName("");
|
|
537
502
|
}
|
|
538
503
|
};
|
|
539
|
-
const handleEdit = (
|
|
540
|
-
|
|
504
|
+
const handleEdit = (box) => {
|
|
505
|
+
setEditingBox(box);
|
|
541
506
|
setIsModalOpen(true);
|
|
542
507
|
};
|
|
543
508
|
const handleCreateNew = () => {
|
|
544
|
-
|
|
509
|
+
setEditingBox(null);
|
|
545
510
|
setIsModalOpen(true);
|
|
546
511
|
};
|
|
547
512
|
const handleModalClose = () => {
|
|
548
513
|
setIsModalOpen(false);
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
};
|
|
552
|
-
const openDeletePrompt = (id, value) => {
|
|
553
|
-
setDeleteAreaId(id);
|
|
554
|
-
setDeleteAreaValue(value);
|
|
514
|
+
setEditingBox(null);
|
|
515
|
+
fetchBoxes();
|
|
555
516
|
};
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
] })
|
|
574
|
-
] }),
|
|
517
|
+
const openDeletePrompt = (id, name) => {
|
|
518
|
+
setDeleteBoxId(id);
|
|
519
|
+
setDeleteBoxName(name);
|
|
520
|
+
};
|
|
521
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
522
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
523
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
|
|
524
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
525
|
+
ui.Input,
|
|
526
|
+
{
|
|
527
|
+
type: "search",
|
|
528
|
+
placeholder: "ค้นหาชื่อกล่อง...",
|
|
529
|
+
value: searchTerm,
|
|
530
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
531
|
+
className: "max-w-md"
|
|
532
|
+
}
|
|
533
|
+
),
|
|
575
534
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
|
|
576
535
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
|
|
577
|
-
"
|
|
536
|
+
"สร้างกล่องใหม่"
|
|
578
537
|
] })
|
|
579
538
|
] }),
|
|
580
539
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
|
|
581
540
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
582
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
583
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
541
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ชื่อ" }),
|
|
542
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ขนาด (กว้าง×ยาว×สูง cm)" }),
|
|
543
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "น้ำหนักสูงสุด (kg)" }),
|
|
544
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
|
|
584
545
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
|
|
585
546
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
|
|
586
547
|
] }) }),
|
|
587
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) :
|
|
588
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
589
|
-
/* @__PURE__ */ jsxRuntime.
|
|
548
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredBoxes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลกล่องพัสดุ" }) }) : filteredBoxes.map((box) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: box.name }),
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
|
|
551
|
+
box.width_cm,
|
|
552
|
+
" × ",
|
|
553
|
+
box.length_cm,
|
|
554
|
+
" × ",
|
|
555
|
+
box.height_cm
|
|
556
|
+
] }),
|
|
557
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: box.max_weight_kg }),
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: box.price_thb.toFixed(2) }),
|
|
590
559
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
591
560
|
ui.Badge,
|
|
592
561
|
{
|
|
593
|
-
color:
|
|
562
|
+
color: box.active ? "green" : "grey",
|
|
594
563
|
className: "cursor-pointer",
|
|
595
|
-
onClick: () => handleToggleActive(
|
|
596
|
-
children:
|
|
564
|
+
onClick: () => handleToggleActive(box),
|
|
565
|
+
children: box.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
|
|
597
566
|
}
|
|
598
567
|
) }),
|
|
599
568
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
@@ -602,7 +571,7 @@ const ServiceAreasTable = () => {
|
|
|
602
571
|
{
|
|
603
572
|
variant: "transparent",
|
|
604
573
|
size: "small",
|
|
605
|
-
onClick: () => handleEdit(
|
|
574
|
+
onClick: () => handleEdit(box),
|
|
606
575
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
|
|
607
576
|
}
|
|
608
577
|
),
|
|
@@ -611,30 +580,30 @@ const ServiceAreasTable = () => {
|
|
|
611
580
|
{
|
|
612
581
|
variant: "transparent",
|
|
613
582
|
size: "small",
|
|
614
|
-
onClick: () => openDeletePrompt(
|
|
583
|
+
onClick: () => openDeletePrompt(box.id, box.name),
|
|
615
584
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
|
|
616
585
|
}
|
|
617
586
|
)
|
|
618
587
|
] }) })
|
|
619
|
-
] },
|
|
588
|
+
] }, box.id)) })
|
|
620
589
|
] })
|
|
621
590
|
] }),
|
|
622
|
-
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
591
|
+
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ParcelBoxModal, { box: editingBox, onClose: handleModalClose }),
|
|
623
592
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
624
593
|
ui.Prompt,
|
|
625
594
|
{
|
|
626
595
|
variant: "confirmation",
|
|
627
|
-
open: !!
|
|
596
|
+
open: !!deleteBoxId,
|
|
628
597
|
onOpenChange: () => {
|
|
629
|
-
|
|
630
|
-
|
|
598
|
+
setDeleteBoxId(null);
|
|
599
|
+
setDeleteBoxName("");
|
|
631
600
|
},
|
|
632
601
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
|
|
633
602
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
|
|
634
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "
|
|
603
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบกล่องพัสดุ" }),
|
|
635
604
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Description, { children: [
|
|
636
|
-
'
|
|
637
|
-
|
|
605
|
+
'คุณต้องการลบกล่อง "',
|
|
606
|
+
deleteBoxName,
|
|
638
607
|
'" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
|
|
639
608
|
] })
|
|
640
609
|
] }),
|
|
@@ -647,65 +616,63 @@ const ServiceAreasTable = () => {
|
|
|
647
616
|
)
|
|
648
617
|
] });
|
|
649
618
|
};
|
|
650
|
-
const
|
|
619
|
+
const BoxesPage = () => {
|
|
651
620
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
652
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
653
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
621
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "กล่องพัสดุ" }) }),
|
|
622
|
+
/* @__PURE__ */ jsxRuntime.jsx(ParcelBoxesTable, {})
|
|
654
623
|
] }) });
|
|
655
624
|
};
|
|
656
625
|
const config$3 = adminSdk.defineRouteConfig({
|
|
657
|
-
icon: icons.
|
|
658
|
-
label: "
|
|
626
|
+
icon: icons.ArchiveBox,
|
|
627
|
+
label: "กล่องพัสดุ"
|
|
659
628
|
});
|
|
660
|
-
const
|
|
629
|
+
const CATEGORIES$1 = [
|
|
630
|
+
{ value: "PACKAGING", label: "วัสดุหีบห่อ" },
|
|
631
|
+
{ value: "PROTECTION", label: "วัสดุป้องกัน" },
|
|
632
|
+
{ value: "FILLING", label: "วัสดุเติมช่องว่าง" },
|
|
633
|
+
{ value: "TAPE", label: "เทป/กาว" },
|
|
634
|
+
{ value: "LABEL", label: "ฉลาก/สติกเกอร์" },
|
|
635
|
+
{ value: "OTHER", label: "อื่นๆ" }
|
|
636
|
+
];
|
|
637
|
+
const MaterialCostModal = ({
|
|
638
|
+
materialCost,
|
|
639
|
+
onClose
|
|
640
|
+
}) => {
|
|
661
641
|
const [formData, setFormData] = react.useState({
|
|
662
642
|
name: "",
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
643
|
+
unit: "",
|
|
644
|
+
cost_per_unit: "",
|
|
645
|
+
currency: "THB",
|
|
646
|
+
category: "",
|
|
647
|
+
description: "",
|
|
668
648
|
active: true
|
|
669
649
|
});
|
|
670
650
|
const [isSaving, setIsSaving] = react.useState(false);
|
|
671
651
|
react.useEffect(() => {
|
|
672
|
-
if (
|
|
652
|
+
if (materialCost) {
|
|
673
653
|
setFormData({
|
|
674
|
-
name:
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
active:
|
|
654
|
+
name: materialCost.name,
|
|
655
|
+
unit: materialCost.unit,
|
|
656
|
+
cost_per_unit: materialCost.cost_per_unit.toString(),
|
|
657
|
+
currency: materialCost.currency,
|
|
658
|
+
category: materialCost.category || "",
|
|
659
|
+
description: materialCost.description || "",
|
|
660
|
+
active: materialCost.active
|
|
681
661
|
});
|
|
682
662
|
}
|
|
683
|
-
}, [
|
|
663
|
+
}, [materialCost]);
|
|
684
664
|
const handleSubmit = async (e) => {
|
|
685
665
|
e.preventDefault();
|
|
686
666
|
const errors = [];
|
|
687
667
|
if (!formData.name.trim()) {
|
|
688
|
-
errors.push("
|
|
689
|
-
}
|
|
690
|
-
const width = parseFloat(formData.width_cm);
|
|
691
|
-
const length = parseFloat(formData.length_cm);
|
|
692
|
-
const height = parseFloat(formData.height_cm);
|
|
693
|
-
const maxWeight = parseFloat(formData.max_weight_kg);
|
|
694
|
-
const price = parseFloat(formData.price_thb);
|
|
695
|
-
if (isNaN(width) || width <= 0) {
|
|
696
|
-
errors.push("ความกว้างต้องเป็นตัวเลขมากกว่า 0");
|
|
697
|
-
}
|
|
698
|
-
if (isNaN(length) || length <= 0) {
|
|
699
|
-
errors.push("ความยาวต้องเป็นตัวเลขมากกว่า 0");
|
|
700
|
-
}
|
|
701
|
-
if (isNaN(height) || height <= 0) {
|
|
702
|
-
errors.push("ความสูงต้องเป็นตัวเลขมากกว่า 0");
|
|
668
|
+
errors.push("กรุณากรอกชื่อวัสดุ");
|
|
703
669
|
}
|
|
704
|
-
if (
|
|
705
|
-
errors.push("
|
|
670
|
+
if (!formData.unit.trim()) {
|
|
671
|
+
errors.push("กรุณากรอกหน่วย");
|
|
706
672
|
}
|
|
707
|
-
|
|
708
|
-
|
|
673
|
+
const costPerUnit = parseFloat(formData.cost_per_unit);
|
|
674
|
+
if (isNaN(costPerUnit) || costPerUnit < 0) {
|
|
675
|
+
errors.push("ต้นทุนต่อหน่วยต้องเป็นตัวเลขไม่ติดลบ");
|
|
709
676
|
}
|
|
710
677
|
if (errors.length > 0) {
|
|
711
678
|
ui.toast.error("ข้อมูลไม่ถูกต้อง", {
|
|
@@ -717,15 +684,15 @@ const ParcelBoxModal = ({ box, onClose }) => {
|
|
|
717
684
|
try {
|
|
718
685
|
const payload = {
|
|
719
686
|
name: formData.name.trim(),
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
687
|
+
unit: formData.unit.trim(),
|
|
688
|
+
cost_per_unit: costPerUnit,
|
|
689
|
+
currency: formData.currency,
|
|
690
|
+
category: formData.category || void 0,
|
|
691
|
+
description: formData.description.trim() || void 0,
|
|
725
692
|
active: formData.active
|
|
726
693
|
};
|
|
727
|
-
const url =
|
|
728
|
-
const method =
|
|
694
|
+
const url = materialCost ? `/admin/material-costs/${materialCost.id}` : "/admin/material-costs";
|
|
695
|
+
const method = materialCost ? "PUT" : "POST";
|
|
729
696
|
const response = await fetch(url, {
|
|
730
697
|
method,
|
|
731
698
|
headers: { "Content-Type": "application/json" },
|
|
@@ -734,7 +701,7 @@ const ParcelBoxModal = ({ box, onClose }) => {
|
|
|
734
701
|
});
|
|
735
702
|
if (response.ok) {
|
|
736
703
|
ui.toast.success("สำเร็จ", {
|
|
737
|
-
description:
|
|
704
|
+
description: materialCost ? "แก้ไขรายการต้นทุนวัสดุแล้ว" : "สร้างรายการต้นทุนวัสดุใหม่แล้ว"
|
|
738
705
|
});
|
|
739
706
|
onClose();
|
|
740
707
|
} else {
|
|
@@ -750,95 +717,87 @@ const ParcelBoxModal = ({ box, onClose }) => {
|
|
|
750
717
|
}
|
|
751
718
|
};
|
|
752
719
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
753
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children:
|
|
720
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: materialCost ? "แก้ไขรายการต้นทุนวัสดุ" : "สร้างรายการต้นทุนวัสดุใหม่" }) }),
|
|
754
721
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
|
|
755
722
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
756
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "name", children: "
|
|
723
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "name", children: "ชื่อวัสดุ *" }),
|
|
757
724
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
758
725
|
ui.Input,
|
|
759
726
|
{
|
|
760
727
|
id: "name",
|
|
761
728
|
value: formData.name,
|
|
762
729
|
onChange: (e) => setFormData({ ...formData, name: e.target.value }),
|
|
763
|
-
placeholder: "เช่น
|
|
730
|
+
placeholder: "เช่น พลาสติกกันกระแทก, กล่องกระดาษ",
|
|
764
731
|
required: true
|
|
765
732
|
}
|
|
766
733
|
)
|
|
767
734
|
] }),
|
|
768
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
769
|
-
/* @__PURE__ */ jsxRuntime.
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
value:
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
] }),
|
|
735
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
736
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "category", children: "หมวดหมู่ (ไม่บังคับ)" }),
|
|
737
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
738
|
+
ui.Select,
|
|
739
|
+
{
|
|
740
|
+
value: formData.category || void 0,
|
|
741
|
+
onValueChange: (value) => setFormData({ ...formData, category: value }),
|
|
742
|
+
children: [
|
|
743
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกหมวดหมู่ (ไม่บังคับ)" }) }),
|
|
744
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES$1.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
|
|
745
|
+
]
|
|
746
|
+
}
|
|
747
|
+
)
|
|
748
|
+
] }),
|
|
749
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
|
|
784
750
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
785
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
751
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "unit", children: "หน่วย *" }),
|
|
786
752
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
787
753
|
ui.Input,
|
|
788
754
|
{
|
|
789
|
-
id: "
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
onChange: (e) => setFormData({ ...formData, length_cm: e.target.value }),
|
|
794
|
-
placeholder: "30",
|
|
755
|
+
id: "unit",
|
|
756
|
+
value: formData.unit,
|
|
757
|
+
onChange: (e) => setFormData({ ...formData, unit: e.target.value }),
|
|
758
|
+
placeholder: "เช่น ชิ้น, เมตร, กิโลกรัม",
|
|
795
759
|
required: true
|
|
796
760
|
}
|
|
797
761
|
)
|
|
798
762
|
] }),
|
|
799
763
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
800
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
764
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "costPerUnit", children: "ต้นทุนต่อหน่วย *" }),
|
|
801
765
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
802
766
|
ui.Input,
|
|
803
767
|
{
|
|
804
|
-
id: "
|
|
768
|
+
id: "costPerUnit",
|
|
805
769
|
type: "number",
|
|
806
|
-
step: "0.
|
|
807
|
-
value: formData.
|
|
808
|
-
onChange: (e) => setFormData({ ...formData,
|
|
809
|
-
placeholder: "
|
|
770
|
+
step: "0.01",
|
|
771
|
+
value: formData.cost_per_unit,
|
|
772
|
+
onChange: (e) => setFormData({ ...formData, cost_per_unit: e.target.value }),
|
|
773
|
+
placeholder: "0.00",
|
|
810
774
|
required: true
|
|
811
775
|
}
|
|
812
776
|
)
|
|
813
777
|
] })
|
|
814
778
|
] }),
|
|
815
779
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
816
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
780
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "currency", children: "สกุลเงิน" }),
|
|
817
781
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
818
782
|
ui.Input,
|
|
819
783
|
{
|
|
820
|
-
id: "
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
|
|
825
|
-
placeholder: "0.5",
|
|
826
|
-
required: true
|
|
784
|
+
id: "currency",
|
|
785
|
+
value: formData.currency,
|
|
786
|
+
onChange: (e) => setFormData({ ...formData, currency: e.target.value }),
|
|
787
|
+
placeholder: "THB"
|
|
827
788
|
}
|
|
828
789
|
)
|
|
829
790
|
] }),
|
|
830
791
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
831
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
792
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "description", children: "คำอธิบาย" }),
|
|
832
793
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
833
|
-
ui.
|
|
794
|
+
ui.Textarea,
|
|
834
795
|
{
|
|
835
|
-
id: "
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
placeholder: "10.00",
|
|
841
|
-
required: true
|
|
796
|
+
id: "description",
|
|
797
|
+
value: formData.description,
|
|
798
|
+
onChange: (e) => setFormData({ ...formData, description: e.target.value }),
|
|
799
|
+
placeholder: "คำอธิบายเพิ่มเติมเกี่ยวกับวัสดุนี้...",
|
|
800
|
+
rows: 3
|
|
842
801
|
}
|
|
843
802
|
)
|
|
844
803
|
] }),
|
|
@@ -851,62 +810,87 @@ const ParcelBoxModal = ({ box, onClose }) => {
|
|
|
851
810
|
onCheckedChange: (checked) => setFormData({ ...formData, active: checked })
|
|
852
811
|
}
|
|
853
812
|
),
|
|
854
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
|
|
855
|
-
] }),
|
|
856
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
857
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
813
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
|
|
814
|
+
] }),
|
|
815
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
816
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
817
|
+
ui.Button,
|
|
818
|
+
{
|
|
819
|
+
type: "button",
|
|
820
|
+
variant: "secondary",
|
|
821
|
+
onClick: onClose,
|
|
822
|
+
disabled: isSaving,
|
|
823
|
+
children: "ยกเลิก"
|
|
824
|
+
}
|
|
825
|
+
),
|
|
858
826
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
|
|
859
827
|
] })
|
|
860
828
|
] }) })
|
|
861
829
|
] }) });
|
|
862
830
|
};
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
831
|
+
const CATEGORIES = [
|
|
832
|
+
{ value: "ALL", label: "ทั้งหมด" },
|
|
833
|
+
{ value: "PACKAGING", label: "วัสดุหีบห่อ" },
|
|
834
|
+
{ value: "PROTECTION", label: "วัสดุป้องกัน" },
|
|
835
|
+
{ value: "FILLING", label: "วัสดุเติมช่องว่าง" },
|
|
836
|
+
{ value: "TAPE", label: "เทป/กาว" },
|
|
837
|
+
{ value: "LABEL", label: "ฉลาก/สติกเกอร์" },
|
|
838
|
+
{ value: "OTHER", label: "อื่นๆ" }
|
|
839
|
+
];
|
|
840
|
+
const MaterialCostsTable = () => {
|
|
841
|
+
const [materialCosts, setMaterialCosts] = react.useState([]);
|
|
842
|
+
const [filteredMaterialCosts, setFilteredMaterialCosts] = react.useState([]);
|
|
866
843
|
const [searchTerm, setSearchTerm] = react.useState("");
|
|
844
|
+
const [categoryFilter, setCategoryFilter] = react.useState("ALL");
|
|
867
845
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
868
|
-
const [
|
|
846
|
+
const [editingMaterialCost, setEditingMaterialCost] = react.useState(null);
|
|
869
847
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
870
|
-
const [
|
|
871
|
-
const [
|
|
848
|
+
const [deleteMaterialCostId, setDeleteMaterialCostId] = react.useState(null);
|
|
849
|
+
const [deleteMaterialCostName, setDeleteMaterialCostName] = react.useState("");
|
|
872
850
|
react.useEffect(() => {
|
|
873
|
-
|
|
851
|
+
fetchMaterialCosts();
|
|
874
852
|
}, []);
|
|
875
853
|
react.useEffect(() => {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
854
|
+
let filtered = materialCosts;
|
|
855
|
+
if (categoryFilter !== "ALL") {
|
|
856
|
+
filtered = filtered.filter((mc) => mc.category === categoryFilter);
|
|
857
|
+
}
|
|
858
|
+
if (searchTerm) {
|
|
859
|
+
filtered = filtered.filter(
|
|
860
|
+
(mc) => mc.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
setFilteredMaterialCosts(filtered);
|
|
864
|
+
}, [searchTerm, categoryFilter, materialCosts]);
|
|
865
|
+
const fetchMaterialCosts = async () => {
|
|
882
866
|
setIsLoading(true);
|
|
883
867
|
try {
|
|
884
|
-
const response = await fetch("/admin/
|
|
868
|
+
const response = await fetch("/admin/material-costs", {
|
|
885
869
|
credentials: "include"
|
|
886
870
|
});
|
|
887
871
|
const data = await response.json();
|
|
888
|
-
|
|
872
|
+
setMaterialCosts(data.material_costs || []);
|
|
889
873
|
} catch (error) {
|
|
890
874
|
ui.toast.error("ข้อผิดพลาด", {
|
|
891
|
-
description: "
|
|
875
|
+
description: "ไม่สามารถโหลดข้อมูลต้นทุนวัสดุได้"
|
|
892
876
|
});
|
|
893
877
|
} finally {
|
|
894
878
|
setIsLoading(false);
|
|
895
879
|
}
|
|
896
880
|
};
|
|
897
|
-
const handleToggleActive = async (
|
|
881
|
+
const handleToggleActive = async (materialCost) => {
|
|
898
882
|
try {
|
|
899
|
-
const response = await fetch(`/admin/
|
|
883
|
+
const response = await fetch(`/admin/material-costs/${materialCost.id}`, {
|
|
900
884
|
method: "PUT",
|
|
901
885
|
headers: { "Content-Type": "application/json" },
|
|
902
886
|
credentials: "include",
|
|
903
|
-
body: JSON.stringify({ ...
|
|
887
|
+
body: JSON.stringify({ ...materialCost, active: !materialCost.active })
|
|
904
888
|
});
|
|
905
889
|
if (response.ok) {
|
|
906
890
|
ui.toast.success("สำเร็จ", {
|
|
907
|
-
description: `${
|
|
891
|
+
description: `${materialCost.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}วัสดุ ${materialCost.name} แล้ว`
|
|
908
892
|
});
|
|
909
|
-
|
|
893
|
+
fetchMaterialCosts();
|
|
910
894
|
} else {
|
|
911
895
|
throw new Error("Failed to update");
|
|
912
896
|
}
|
|
@@ -917,91 +901,105 @@ const ParcelBoxesTable = () => {
|
|
|
917
901
|
}
|
|
918
902
|
};
|
|
919
903
|
const handleDelete = async () => {
|
|
920
|
-
if (!
|
|
904
|
+
if (!deleteMaterialCostId) return;
|
|
921
905
|
try {
|
|
922
|
-
const response = await fetch(
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
906
|
+
const response = await fetch(
|
|
907
|
+
`/admin/material-costs/${deleteMaterialCostId}`,
|
|
908
|
+
{
|
|
909
|
+
method: "DELETE",
|
|
910
|
+
credentials: "include"
|
|
911
|
+
}
|
|
912
|
+
);
|
|
926
913
|
if (response.ok) {
|
|
927
914
|
ui.toast.success("สำเร็จ", {
|
|
928
|
-
description:
|
|
915
|
+
description: `ลบวัสดุ ${deleteMaterialCostName} แล้ว`
|
|
929
916
|
});
|
|
930
|
-
|
|
917
|
+
fetchMaterialCosts();
|
|
931
918
|
} else {
|
|
932
919
|
throw new Error("Failed to delete");
|
|
933
920
|
}
|
|
934
921
|
} catch (error) {
|
|
935
922
|
ui.toast.error("ข้อผิดพลาด", {
|
|
936
|
-
description: "
|
|
923
|
+
description: "ไม่สามารถลบวัสดุได้"
|
|
937
924
|
});
|
|
938
925
|
} finally {
|
|
939
|
-
|
|
940
|
-
|
|
926
|
+
setDeleteMaterialCostId(null);
|
|
927
|
+
setDeleteMaterialCostName("");
|
|
941
928
|
}
|
|
942
929
|
};
|
|
943
|
-
const handleEdit = (
|
|
944
|
-
|
|
930
|
+
const handleEdit = (materialCost) => {
|
|
931
|
+
setEditingMaterialCost(materialCost);
|
|
945
932
|
setIsModalOpen(true);
|
|
946
933
|
};
|
|
947
934
|
const handleCreateNew = () => {
|
|
948
|
-
|
|
935
|
+
setEditingMaterialCost(null);
|
|
949
936
|
setIsModalOpen(true);
|
|
950
937
|
};
|
|
951
938
|
const handleModalClose = () => {
|
|
952
939
|
setIsModalOpen(false);
|
|
953
|
-
|
|
954
|
-
|
|
940
|
+
setEditingMaterialCost(null);
|
|
941
|
+
fetchMaterialCosts();
|
|
955
942
|
};
|
|
956
943
|
const openDeletePrompt = (id, name) => {
|
|
957
|
-
|
|
958
|
-
|
|
944
|
+
setDeleteMaterialCostId(id);
|
|
945
|
+
setDeleteMaterialCostName(name);
|
|
946
|
+
};
|
|
947
|
+
const getCategoryLabel = (category) => {
|
|
948
|
+
var _a;
|
|
949
|
+
if (!category) return "-";
|
|
950
|
+
return ((_a = CATEGORIES.find((c) => c.value === category)) == null ? void 0 : _a.label) || category;
|
|
959
951
|
};
|
|
960
952
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
961
953
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
962
954
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
|
|
963
|
-
/* @__PURE__ */ jsxRuntime.
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
955
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 flex-1", children: [
|
|
956
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
957
|
+
ui.Input,
|
|
958
|
+
{
|
|
959
|
+
type: "search",
|
|
960
|
+
placeholder: "ค้นหาชื่อวัสดุ...",
|
|
961
|
+
value: searchTerm,
|
|
962
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
963
|
+
className: "max-w-md"
|
|
964
|
+
}
|
|
965
|
+
),
|
|
966
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: categoryFilter, onValueChange: setCategoryFilter, children: [
|
|
967
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "หมวดหมู่" }) }),
|
|
968
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
|
|
969
|
+
] })
|
|
970
|
+
] }),
|
|
973
971
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
|
|
974
972
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
|
|
975
|
-
"
|
|
973
|
+
"สร้างรายการใหม่"
|
|
976
974
|
] })
|
|
977
975
|
] }),
|
|
978
976
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
|
|
979
977
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
980
978
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ชื่อ" }),
|
|
981
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
982
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
983
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
979
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หมวดหมู่" }),
|
|
980
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หน่วย" }),
|
|
981
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ต้นทุนต่อหน่วย" }),
|
|
982
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "คำอธิบาย" }),
|
|
984
983
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
|
|
985
984
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
|
|
986
985
|
] }) }),
|
|
987
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) :
|
|
988
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
986
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredMaterialCosts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลต้นทุนวัสดุ" }) }) : filteredMaterialCosts.map((materialCost) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
987
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.name }),
|
|
988
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: getCategoryLabel(materialCost.category) }) }),
|
|
989
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.unit }),
|
|
989
990
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
|
|
990
|
-
|
|
991
|
-
"
|
|
992
|
-
|
|
993
|
-
" × ",
|
|
994
|
-
box.height_cm
|
|
991
|
+
materialCost.cost_per_unit.toFixed(2),
|
|
992
|
+
" ",
|
|
993
|
+
materialCost.currency
|
|
995
994
|
] }),
|
|
996
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
997
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: box.price_thb.toFixed(2) }),
|
|
995
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-xs truncate", children: materialCost.description || "-" }),
|
|
998
996
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
999
997
|
ui.Badge,
|
|
1000
998
|
{
|
|
1001
|
-
color:
|
|
999
|
+
color: materialCost.active ? "green" : "grey",
|
|
1002
1000
|
className: "cursor-pointer",
|
|
1003
|
-
onClick: () => handleToggleActive(
|
|
1004
|
-
children:
|
|
1001
|
+
onClick: () => handleToggleActive(materialCost),
|
|
1002
|
+
children: materialCost.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
|
|
1005
1003
|
}
|
|
1006
1004
|
) }),
|
|
1007
1005
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
@@ -1010,7 +1008,7 @@ const ParcelBoxesTable = () => {
|
|
|
1010
1008
|
{
|
|
1011
1009
|
variant: "transparent",
|
|
1012
1010
|
size: "small",
|
|
1013
|
-
onClick: () => handleEdit(
|
|
1011
|
+
onClick: () => handleEdit(materialCost),
|
|
1014
1012
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
|
|
1015
1013
|
}
|
|
1016
1014
|
),
|
|
@@ -1019,30 +1017,36 @@ const ParcelBoxesTable = () => {
|
|
|
1019
1017
|
{
|
|
1020
1018
|
variant: "transparent",
|
|
1021
1019
|
size: "small",
|
|
1022
|
-
onClick: () => openDeletePrompt(
|
|
1020
|
+
onClick: () => openDeletePrompt(materialCost.id, materialCost.name),
|
|
1023
1021
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
|
|
1024
1022
|
}
|
|
1025
1023
|
)
|
|
1026
1024
|
] }) })
|
|
1027
|
-
] },
|
|
1025
|
+
] }, materialCost.id)) })
|
|
1028
1026
|
] })
|
|
1029
1027
|
] }),
|
|
1030
|
-
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1028
|
+
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1029
|
+
MaterialCostModal,
|
|
1030
|
+
{
|
|
1031
|
+
materialCost: editingMaterialCost,
|
|
1032
|
+
onClose: handleModalClose
|
|
1033
|
+
}
|
|
1034
|
+
),
|
|
1031
1035
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1032
1036
|
ui.Prompt,
|
|
1033
1037
|
{
|
|
1034
1038
|
variant: "confirmation",
|
|
1035
|
-
open: !!
|
|
1039
|
+
open: !!deleteMaterialCostId,
|
|
1036
1040
|
onOpenChange: () => {
|
|
1037
|
-
|
|
1038
|
-
|
|
1041
|
+
setDeleteMaterialCostId(null);
|
|
1042
|
+
setDeleteMaterialCostName("");
|
|
1039
1043
|
},
|
|
1040
1044
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
|
|
1041
1045
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
|
|
1042
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "
|
|
1046
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบรายการต้นทุนวัสดุ" }),
|
|
1043
1047
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Description, { children: [
|
|
1044
|
-
'
|
|
1045
|
-
|
|
1048
|
+
'คุณต้องการลบวัสดุ "',
|
|
1049
|
+
deleteMaterialCostName,
|
|
1046
1050
|
'" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
|
|
1047
1051
|
] })
|
|
1048
1052
|
] }),
|
|
@@ -1055,63 +1059,97 @@ const ParcelBoxesTable = () => {
|
|
|
1055
1059
|
)
|
|
1056
1060
|
] });
|
|
1057
1061
|
};
|
|
1058
|
-
const
|
|
1062
|
+
const MaterialCostsPage = () => {
|
|
1059
1063
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
1060
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
1061
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1064
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "ต้นทุนวัสดุ" }) }),
|
|
1065
|
+
/* @__PURE__ */ jsxRuntime.jsx(MaterialCostsTable, {})
|
|
1062
1066
|
] }) });
|
|
1063
1067
|
};
|
|
1064
1068
|
const config$2 = adminSdk.defineRouteConfig({
|
|
1065
|
-
icon: icons.
|
|
1066
|
-
label: "
|
|
1069
|
+
icon: icons.CurrencyDollarSolid,
|
|
1070
|
+
label: "ต้นทุนวัสดุ"
|
|
1067
1071
|
});
|
|
1068
|
-
const
|
|
1069
|
-
{ value: "
|
|
1070
|
-
{ value: "
|
|
1071
|
-
{ value: "
|
|
1072
|
-
{ value: "TAPE", label: "เทป/กาว" },
|
|
1073
|
-
{ value: "LABEL", label: "ฉลาก/สติกเกอร์" },
|
|
1074
|
-
{ value: "OTHER", label: "อื่นๆ" }
|
|
1072
|
+
const CARRIER_TYPES$1 = [
|
|
1073
|
+
{ value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
|
|
1074
|
+
{ value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
|
|
1075
|
+
{ value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
|
|
1075
1076
|
];
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1077
|
+
const SERVICE_CODES$1 = [
|
|
1078
|
+
{ value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม.", usesHours: true },
|
|
1079
|
+
{ value: "SAME_DAY", label: "ส่งด่วนภายในวัน", usesHours: true },
|
|
1080
|
+
{ value: "STANDARD_3_5D", label: "EMS 3-5 วัน", usesHours: false },
|
|
1081
|
+
{ value: "EXPRESS_1_2D", label: "Express 1-2 วัน", usesHours: false }
|
|
1082
|
+
];
|
|
1083
|
+
const ShippingRateModal = ({ rate, onClose }) => {
|
|
1080
1084
|
const [formData, setFormData] = react.useState({
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1085
|
+
carrier_type: "COMPANY_FLEET",
|
|
1086
|
+
service_code: "MESSENGER_3H",
|
|
1087
|
+
max_weight_kg: "",
|
|
1088
|
+
price: "",
|
|
1084
1089
|
currency: "THB",
|
|
1085
|
-
|
|
1086
|
-
|
|
1090
|
+
priority: "0",
|
|
1091
|
+
eta_hours_min: "",
|
|
1092
|
+
eta_hours_max: "",
|
|
1093
|
+
eta_days_min: "",
|
|
1094
|
+
eta_days_max: "",
|
|
1087
1095
|
active: true
|
|
1088
1096
|
});
|
|
1089
1097
|
const [isSaving, setIsSaving] = react.useState(false);
|
|
1098
|
+
const selectedService = SERVICE_CODES$1.find((s) => s.value === formData.service_code);
|
|
1099
|
+
const usesHours = (selectedService == null ? void 0 : selectedService.usesHours) ?? false;
|
|
1090
1100
|
react.useEffect(() => {
|
|
1091
|
-
|
|
1101
|
+
var _a, _b, _c, _d;
|
|
1102
|
+
if (rate) {
|
|
1092
1103
|
setFormData({
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1104
|
+
carrier_type: rate.carrier_type,
|
|
1105
|
+
service_code: rate.service_code,
|
|
1106
|
+
max_weight_kg: rate.max_weight_kg.toString(),
|
|
1107
|
+
price: rate.price.toString(),
|
|
1108
|
+
currency: rate.currency,
|
|
1109
|
+
priority: (rate.priority ?? 0).toString(),
|
|
1110
|
+
eta_hours_min: ((_a = rate.eta_hours_min) == null ? void 0 : _a.toString()) || "",
|
|
1111
|
+
eta_hours_max: ((_b = rate.eta_hours_max) == null ? void 0 : _b.toString()) || "",
|
|
1112
|
+
eta_days_min: ((_c = rate.eta_days_min) == null ? void 0 : _c.toString()) || "",
|
|
1113
|
+
eta_days_max: ((_d = rate.eta_days_max) == null ? void 0 : _d.toString()) || "",
|
|
1114
|
+
active: rate.active
|
|
1100
1115
|
});
|
|
1101
1116
|
}
|
|
1102
|
-
}, [
|
|
1117
|
+
}, [rate]);
|
|
1103
1118
|
const handleSubmit = async (e) => {
|
|
1104
1119
|
e.preventDefault();
|
|
1105
1120
|
const errors = [];
|
|
1106
|
-
|
|
1107
|
-
|
|
1121
|
+
const maxWeight = parseFloat(formData.max_weight_kg);
|
|
1122
|
+
const price = parseFloat(formData.price);
|
|
1123
|
+
const priority = parseInt(formData.priority);
|
|
1124
|
+
if (isNaN(maxWeight) || maxWeight <= 0) {
|
|
1125
|
+
errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
|
|
1108
1126
|
}
|
|
1109
|
-
if (
|
|
1110
|
-
errors.push("
|
|
1127
|
+
if (isNaN(price) || price < 0) {
|
|
1128
|
+
errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
|
|
1111
1129
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1130
|
+
if (isNaN(priority)) {
|
|
1131
|
+
errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
|
|
1132
|
+
}
|
|
1133
|
+
let etaHoursMin;
|
|
1134
|
+
let etaHoursMax;
|
|
1135
|
+
let etaDaysMin;
|
|
1136
|
+
let etaDaysMax;
|
|
1137
|
+
if (usesHours) {
|
|
1138
|
+
etaHoursMin = formData.eta_hours_min ? parseFloat(formData.eta_hours_min) : void 0;
|
|
1139
|
+
etaHoursMax = formData.eta_hours_max ? parseFloat(formData.eta_hours_max) : void 0;
|
|
1140
|
+
if (etaHoursMin === void 0 || etaHoursMax === void 0) {
|
|
1141
|
+
errors.push("กรุณากรอก ETA เป็นชั่วโมงให้ครบ");
|
|
1142
|
+
} else if (etaHoursMin > etaHoursMax) {
|
|
1143
|
+
errors.push("ETA ชั่วโมงต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
|
|
1144
|
+
}
|
|
1145
|
+
} else {
|
|
1146
|
+
etaDaysMin = formData.eta_days_min ? parseFloat(formData.eta_days_min) : void 0;
|
|
1147
|
+
etaDaysMax = formData.eta_days_max ? parseFloat(formData.eta_days_max) : void 0;
|
|
1148
|
+
if (etaDaysMin === void 0 || etaDaysMax === void 0) {
|
|
1149
|
+
errors.push("กรุณากรอก ETA เป็นวันให้ครบ");
|
|
1150
|
+
} else if (etaDaysMin > etaDaysMax) {
|
|
1151
|
+
errors.push("ETA วันต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
|
|
1152
|
+
}
|
|
1115
1153
|
}
|
|
1116
1154
|
if (errors.length > 0) {
|
|
1117
1155
|
ui.toast.error("ข้อมูลไม่ถูกต้อง", {
|
|
@@ -1122,16 +1160,23 @@ const MaterialCostModal = ({
|
|
|
1122
1160
|
setIsSaving(true);
|
|
1123
1161
|
try {
|
|
1124
1162
|
const payload = {
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1163
|
+
carrier_type: formData.carrier_type,
|
|
1164
|
+
service_code: formData.service_code,
|
|
1165
|
+
max_weight_kg: maxWeight,
|
|
1166
|
+
price,
|
|
1128
1167
|
currency: formData.currency,
|
|
1129
|
-
|
|
1130
|
-
description: formData.description.trim() || void 0,
|
|
1168
|
+
priority,
|
|
1131
1169
|
active: formData.active
|
|
1132
1170
|
};
|
|
1133
|
-
|
|
1134
|
-
|
|
1171
|
+
if (usesHours) {
|
|
1172
|
+
payload.eta_hours_min = etaHoursMin;
|
|
1173
|
+
payload.eta_hours_max = etaHoursMax;
|
|
1174
|
+
} else {
|
|
1175
|
+
payload.eta_days_min = etaDaysMin;
|
|
1176
|
+
payload.eta_days_max = etaDaysMax;
|
|
1177
|
+
}
|
|
1178
|
+
const url = rate ? `/admin/shipping-rates/${rate.id}` : "/admin/shipping-rates";
|
|
1179
|
+
const method = rate ? "PUT" : "POST";
|
|
1135
1180
|
const response = await fetch(url, {
|
|
1136
1181
|
method,
|
|
1137
1182
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1140,7 +1185,7 @@ const MaterialCostModal = ({
|
|
|
1140
1185
|
});
|
|
1141
1186
|
if (response.ok) {
|
|
1142
1187
|
ui.toast.success("สำเร็จ", {
|
|
1143
|
-
description:
|
|
1188
|
+
description: rate ? "แก้ไขอัตราค่าขนส่งแล้ว" : "สร้างอัตราค่าขนส่งใหม่แล้ว"
|
|
1144
1189
|
});
|
|
1145
1190
|
onClose();
|
|
1146
1191
|
} else {
|
|
@@ -1156,89 +1201,139 @@ const MaterialCostModal = ({
|
|
|
1156
1201
|
}
|
|
1157
1202
|
};
|
|
1158
1203
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
1159
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children:
|
|
1204
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: rate ? "แก้ไขอัตราค่าขนส่ง" : "สร้างอัตราค่าขนส่งใหม่" }) }),
|
|
1160
1205
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
|
|
1161
1206
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1162
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1163
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1164
|
-
ui.
|
|
1207
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "carrier", children: "ประเภทขนส่ง *" }),
|
|
1208
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1209
|
+
ui.Select,
|
|
1165
1210
|
{
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1211
|
+
value: formData.carrier_type,
|
|
1212
|
+
onValueChange: (value) => setFormData({ ...formData, carrier_type: value }),
|
|
1213
|
+
children: [
|
|
1214
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกประเภทขนส่ง" }) }),
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES$1.map((carrier) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: carrier.value, children: carrier.label }, carrier.value)) })
|
|
1216
|
+
]
|
|
1171
1217
|
}
|
|
1172
1218
|
)
|
|
1173
1219
|
] }),
|
|
1174
1220
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1175
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1221
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "service", children: "บริการจัดส่ง *" }),
|
|
1176
1222
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1177
1223
|
ui.Select,
|
|
1178
1224
|
{
|
|
1179
|
-
value: formData.
|
|
1180
|
-
onValueChange: (value) => setFormData({
|
|
1225
|
+
value: formData.service_code,
|
|
1226
|
+
onValueChange: (value) => setFormData({
|
|
1227
|
+
...formData,
|
|
1228
|
+
service_code: value,
|
|
1229
|
+
eta_hours_min: "",
|
|
1230
|
+
eta_hours_max: "",
|
|
1231
|
+
eta_days_min: "",
|
|
1232
|
+
eta_days_max: ""
|
|
1233
|
+
}),
|
|
1181
1234
|
children: [
|
|
1182
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "
|
|
1183
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children:
|
|
1235
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกบริการ" }) }),
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES$1.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
|
|
1184
1237
|
]
|
|
1185
1238
|
}
|
|
1186
1239
|
)
|
|
1187
1240
|
] }),
|
|
1188
1241
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
|
|
1189
1242
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1190
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1243
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
|
|
1191
1244
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1192
1245
|
ui.Input,
|
|
1193
1246
|
{
|
|
1194
|
-
id: "
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1247
|
+
id: "maxWeight",
|
|
1248
|
+
type: "number",
|
|
1249
|
+
step: "0.1",
|
|
1250
|
+
min: "0",
|
|
1251
|
+
value: formData.max_weight_kg,
|
|
1252
|
+
onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
|
|
1253
|
+
placeholder: "เช่น 3",
|
|
1198
1254
|
required: true
|
|
1199
1255
|
}
|
|
1200
1256
|
)
|
|
1201
1257
|
] }),
|
|
1202
1258
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1203
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1259
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
|
|
1204
1260
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1205
1261
|
ui.Input,
|
|
1206
1262
|
{
|
|
1207
|
-
id: "
|
|
1263
|
+
id: "price",
|
|
1208
1264
|
type: "number",
|
|
1209
1265
|
step: "0.01",
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1266
|
+
min: "0",
|
|
1267
|
+
value: formData.price,
|
|
1268
|
+
onChange: (e) => setFormData({ ...formData, price: e.target.value }),
|
|
1269
|
+
placeholder: "เช่น 80",
|
|
1213
1270
|
required: true
|
|
1214
1271
|
}
|
|
1215
1272
|
)
|
|
1216
1273
|
] })
|
|
1217
1274
|
] }),
|
|
1218
1275
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1219
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1276
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
|
|
1220
1277
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1221
1278
|
ui.Input,
|
|
1222
1279
|
{
|
|
1223
|
-
id: "
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1280
|
+
id: "priority",
|
|
1281
|
+
type: "number",
|
|
1282
|
+
value: formData.priority,
|
|
1283
|
+
onChange: (e) => setFormData({ ...formData, priority: e.target.value }),
|
|
1284
|
+
placeholder: "0"
|
|
1227
1285
|
}
|
|
1228
|
-
)
|
|
1286
|
+
),
|
|
1287
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ตัวเลขสูงกว่าจะถูกเสนอให้เลือกก่อน (ค่าเริ่มต้น 0)" })
|
|
1229
1288
|
] }),
|
|
1230
1289
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1231
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1290
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Label, { children: [
|
|
1291
|
+
usesHours ? "ETA (ชั่วโมง)" : "ETA (วัน)",
|
|
1292
|
+
" *"
|
|
1293
|
+
] }),
|
|
1294
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 mt-2", children: usesHours ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1295
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1296
|
+
ui.Input,
|
|
1297
|
+
{
|
|
1298
|
+
type: "number",
|
|
1299
|
+
placeholder: "ต่ำสุด",
|
|
1300
|
+
value: formData.eta_hours_min,
|
|
1301
|
+
onChange: (e) => setFormData({ ...formData, eta_hours_min: e.target.value }),
|
|
1302
|
+
required: true
|
|
1303
|
+
}
|
|
1304
|
+
),
|
|
1305
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1306
|
+
ui.Input,
|
|
1307
|
+
{
|
|
1308
|
+
type: "number",
|
|
1309
|
+
placeholder: "สูงสุด",
|
|
1310
|
+
value: formData.eta_hours_max,
|
|
1311
|
+
onChange: (e) => setFormData({ ...formData, eta_hours_max: e.target.value }),
|
|
1312
|
+
required: true
|
|
1313
|
+
}
|
|
1314
|
+
)
|
|
1315
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1316
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1317
|
+
ui.Input,
|
|
1318
|
+
{
|
|
1319
|
+
type: "number",
|
|
1320
|
+
placeholder: "ต่ำสุด",
|
|
1321
|
+
value: formData.eta_days_min,
|
|
1322
|
+
onChange: (e) => setFormData({ ...formData, eta_days_min: e.target.value }),
|
|
1323
|
+
required: true
|
|
1324
|
+
}
|
|
1325
|
+
),
|
|
1326
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1327
|
+
ui.Input,
|
|
1328
|
+
{
|
|
1329
|
+
type: "number",
|
|
1330
|
+
placeholder: "สูงสุด",
|
|
1331
|
+
value: formData.eta_days_max,
|
|
1332
|
+
onChange: (e) => setFormData({ ...formData, eta_days_max: e.target.value }),
|
|
1333
|
+
required: true
|
|
1334
|
+
}
|
|
1335
|
+
)
|
|
1336
|
+
] }) })
|
|
1242
1337
|
] }),
|
|
1243
1338
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
1244
1339
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1252,202 +1347,168 @@ const MaterialCostModal = ({
|
|
|
1252
1347
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
|
|
1253
1348
|
] }),
|
|
1254
1349
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
1255
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1256
|
-
ui.Button,
|
|
1257
|
-
{
|
|
1258
|
-
type: "button",
|
|
1259
|
-
variant: "secondary",
|
|
1260
|
-
onClick: onClose,
|
|
1261
|
-
disabled: isSaving,
|
|
1262
|
-
children: "ยกเลิก"
|
|
1263
|
-
}
|
|
1264
|
-
),
|
|
1350
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
|
|
1265
1351
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
|
|
1266
1352
|
] })
|
|
1267
1353
|
] }) })
|
|
1268
1354
|
] }) });
|
|
1269
1355
|
};
|
|
1270
|
-
const
|
|
1356
|
+
const CARRIER_TYPES = [
|
|
1271
1357
|
{ value: "ALL", label: "ทั้งหมด" },
|
|
1272
|
-
{ value: "
|
|
1273
|
-
{ value: "
|
|
1274
|
-
{ value: "
|
|
1275
|
-
{ value: "TAPE", label: "เทป/กาว" },
|
|
1276
|
-
{ value: "LABEL", label: "ฉลาก/สติกเกอร์" },
|
|
1277
|
-
{ value: "OTHER", label: "อื่นๆ" }
|
|
1358
|
+
{ value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
|
|
1359
|
+
{ value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
|
|
1360
|
+
{ value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
|
|
1278
1361
|
];
|
|
1279
|
-
const
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1362
|
+
const SERVICE_CODES = [
|
|
1363
|
+
{ value: "ALL", label: "ทั้งหมด" },
|
|
1364
|
+
{ value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม." },
|
|
1365
|
+
{ value: "SAME_DAY", label: "ส่งด่วนภายในวัน" },
|
|
1366
|
+
{ value: "STANDARD_3_5D", label: "EMS 3-5 วัน" },
|
|
1367
|
+
{ value: "EXPRESS_1_2D", label: "Express 1-2 วัน" }
|
|
1368
|
+
];
|
|
1369
|
+
const ShippingRatesTable = () => {
|
|
1370
|
+
const [rates, setRates] = react.useState([]);
|
|
1371
|
+
const [filteredRates, setFilteredRates] = react.useState([]);
|
|
1372
|
+
const [carrierFilter, setCarrierFilter] = react.useState("ALL");
|
|
1373
|
+
const [serviceFilter, setServiceFilter] = react.useState("ALL");
|
|
1284
1374
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
1285
|
-
const [
|
|
1375
|
+
const [editingRate, setEditingRate] = react.useState(null);
|
|
1286
1376
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
1287
|
-
const [
|
|
1288
|
-
const [deleteMaterialCostName, setDeleteMaterialCostName] = react.useState("");
|
|
1377
|
+
const [deleteRateId, setDeleteRateId] = react.useState(null);
|
|
1289
1378
|
react.useEffect(() => {
|
|
1290
|
-
|
|
1379
|
+
fetchRates();
|
|
1291
1380
|
}, []);
|
|
1292
1381
|
react.useEffect(() => {
|
|
1293
|
-
let filtered =
|
|
1294
|
-
if (
|
|
1295
|
-
filtered = filtered.filter((
|
|
1296
|
-
}
|
|
1297
|
-
if (searchTerm) {
|
|
1298
|
-
filtered = filtered.filter(
|
|
1299
|
-
(mc) => mc.name.toLowerCase().includes(searchTerm.toLowerCase())
|
|
1300
|
-
);
|
|
1382
|
+
let filtered = rates;
|
|
1383
|
+
if (carrierFilter !== "ALL") {
|
|
1384
|
+
filtered = filtered.filter((rate) => rate.carrier_type === carrierFilter);
|
|
1301
1385
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1386
|
+
if (serviceFilter !== "ALL") {
|
|
1387
|
+
filtered = filtered.filter((rate) => rate.service_code === serviceFilter);
|
|
1388
|
+
}
|
|
1389
|
+
setFilteredRates(filtered);
|
|
1390
|
+
}, [carrierFilter, serviceFilter, rates]);
|
|
1391
|
+
const fetchRates = async () => {
|
|
1305
1392
|
setIsLoading(true);
|
|
1306
1393
|
try {
|
|
1307
|
-
const response = await fetch("/admin/
|
|
1394
|
+
const response = await fetch("/admin/shipping-rates", {
|
|
1308
1395
|
credentials: "include"
|
|
1309
1396
|
});
|
|
1310
1397
|
const data = await response.json();
|
|
1311
|
-
|
|
1398
|
+
setRates(data.rates || []);
|
|
1312
1399
|
} catch (error) {
|
|
1313
1400
|
ui.toast.error("ข้อผิดพลาด", {
|
|
1314
|
-
description: "
|
|
1401
|
+
description: "ไม่สามารถโหลดข้อมูลอัตราค่าขนส่งได้"
|
|
1315
1402
|
});
|
|
1316
1403
|
} finally {
|
|
1317
1404
|
setIsLoading(false);
|
|
1318
1405
|
}
|
|
1319
1406
|
};
|
|
1320
|
-
const handleToggleActive = async (materialCost) => {
|
|
1321
|
-
try {
|
|
1322
|
-
const response = await fetch(`/admin/material-costs/${materialCost.id}`, {
|
|
1323
|
-
method: "PUT",
|
|
1324
|
-
headers: { "Content-Type": "application/json" },
|
|
1325
|
-
credentials: "include",
|
|
1326
|
-
body: JSON.stringify({ ...materialCost, active: !materialCost.active })
|
|
1327
|
-
});
|
|
1328
|
-
if (response.ok) {
|
|
1329
|
-
ui.toast.success("สำเร็จ", {
|
|
1330
|
-
description: `${materialCost.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}วัสดุ ${materialCost.name} แล้ว`
|
|
1331
|
-
});
|
|
1332
|
-
fetchMaterialCosts();
|
|
1333
|
-
} else {
|
|
1334
|
-
throw new Error("Failed to update");
|
|
1335
|
-
}
|
|
1336
|
-
} catch (error) {
|
|
1337
|
-
ui.toast.error("ข้อผิดพลาด", {
|
|
1338
|
-
description: "ไม่สามารถอัพเดทสถานะได้"
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1341
|
-
};
|
|
1342
1407
|
const handleDelete = async () => {
|
|
1343
|
-
if (!
|
|
1408
|
+
if (!deleteRateId) return;
|
|
1344
1409
|
try {
|
|
1345
|
-
const response = await fetch(
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
credentials: "include"
|
|
1350
|
-
}
|
|
1351
|
-
);
|
|
1410
|
+
const response = await fetch(`/admin/shipping-rates/${deleteRateId}`, {
|
|
1411
|
+
method: "DELETE",
|
|
1412
|
+
credentials: "include"
|
|
1413
|
+
});
|
|
1352
1414
|
if (response.ok) {
|
|
1353
1415
|
ui.toast.success("สำเร็จ", {
|
|
1354
|
-
description:
|
|
1416
|
+
description: "ลบอัตราค่าขนส่งแล้ว"
|
|
1355
1417
|
});
|
|
1356
|
-
|
|
1418
|
+
fetchRates();
|
|
1357
1419
|
} else {
|
|
1358
1420
|
throw new Error("Failed to delete");
|
|
1359
1421
|
}
|
|
1360
1422
|
} catch (error) {
|
|
1361
1423
|
ui.toast.error("ข้อผิดพลาด", {
|
|
1362
|
-
description: "
|
|
1424
|
+
description: "ไม่สามารถลบอัตราค่าขนส่งได้"
|
|
1363
1425
|
});
|
|
1364
1426
|
} finally {
|
|
1365
|
-
|
|
1366
|
-
setDeleteMaterialCostName("");
|
|
1427
|
+
setDeleteRateId(null);
|
|
1367
1428
|
}
|
|
1368
1429
|
};
|
|
1369
|
-
const handleEdit = (
|
|
1370
|
-
|
|
1430
|
+
const handleEdit = (rate) => {
|
|
1431
|
+
setEditingRate(rate);
|
|
1371
1432
|
setIsModalOpen(true);
|
|
1372
1433
|
};
|
|
1373
1434
|
const handleCreateNew = () => {
|
|
1374
|
-
|
|
1435
|
+
setEditingRate(null);
|
|
1375
1436
|
setIsModalOpen(true);
|
|
1376
1437
|
};
|
|
1377
1438
|
const handleModalClose = () => {
|
|
1378
1439
|
setIsModalOpen(false);
|
|
1379
|
-
|
|
1380
|
-
|
|
1440
|
+
setEditingRate(null);
|
|
1441
|
+
fetchRates();
|
|
1381
1442
|
};
|
|
1382
|
-
const
|
|
1383
|
-
|
|
1384
|
-
|
|
1443
|
+
const getCarrierLabel = (type) => {
|
|
1444
|
+
var _a;
|
|
1445
|
+
return ((_a = CARRIER_TYPES.find((c) => c.value === type)) == null ? void 0 : _a.label) || type;
|
|
1385
1446
|
};
|
|
1386
|
-
const
|
|
1447
|
+
const getServiceLabel = (code) => {
|
|
1387
1448
|
var _a;
|
|
1388
|
-
|
|
1389
|
-
|
|
1449
|
+
return ((_a = SERVICE_CODES.find((s) => s.value === code)) == null ? void 0 : _a.label) || code;
|
|
1450
|
+
};
|
|
1451
|
+
const formatETA = (rate) => {
|
|
1452
|
+
if (rate.eta_hours_min !== null && rate.eta_hours_min !== void 0 && rate.eta_hours_max !== null && rate.eta_hours_max !== void 0) {
|
|
1453
|
+
return `${rate.eta_hours_min}-${rate.eta_hours_max} ชม.`;
|
|
1454
|
+
}
|
|
1455
|
+
if (rate.eta_days_min !== null && rate.eta_days_min !== void 0 && rate.eta_days_max !== null && rate.eta_days_max !== void 0) {
|
|
1456
|
+
return `${rate.eta_days_min}-${rate.eta_days_max} วัน`;
|
|
1457
|
+
}
|
|
1458
|
+
return "-";
|
|
1390
1459
|
};
|
|
1391
1460
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1392
1461
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
1393
1462
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
|
|
1394
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4
|
|
1395
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1396
|
-
|
|
1397
|
-
{
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1463
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 items-end", children: [
|
|
1464
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
1465
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "ประเภทขนส่ง" }),
|
|
1466
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: carrierFilter, onValueChange: setCarrierFilter, children: [
|
|
1467
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
|
|
1468
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES.map((type) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: type.value, children: type.label }, type.value)) })
|
|
1469
|
+
] })
|
|
1470
|
+
] }),
|
|
1471
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
1472
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "บริการจัดส่ง" }),
|
|
1473
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: serviceFilter, onValueChange: setServiceFilter, children: [
|
|
1474
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
|
|
1475
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
|
|
1476
|
+
] })
|
|
1408
1477
|
] })
|
|
1409
1478
|
] }),
|
|
1410
1479
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
|
|
1411
1480
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
|
|
1412
|
-
"
|
|
1481
|
+
"สร้างอัตราใหม่"
|
|
1413
1482
|
] })
|
|
1414
1483
|
] }),
|
|
1415
1484
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
|
|
1416
1485
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
1417
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1418
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1419
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1420
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1421
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1486
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ประเภทขนส่ง" }),
|
|
1487
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "บริการ" }),
|
|
1488
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "น้ำหนัก ≤ (kg)" }),
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ETA" }),
|
|
1422
1491
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
|
|
1423
1492
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
|
|
1424
1493
|
] }) }),
|
|
1425
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) :
|
|
1426
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
1427
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
1428
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.unit }),
|
|
1494
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredRates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลอัตราค่าขนส่ง" }) }) : filteredRates.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
1495
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getCarrierLabel(rate.carrier_type) }),
|
|
1496
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getServiceLabel(rate.service_code) }),
|
|
1429
1497
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1498
|
+
"≤ ",
|
|
1499
|
+
rate.max_weight_kg,
|
|
1500
|
+
" kg"
|
|
1433
1501
|
] }),
|
|
1434
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, {
|
|
1435
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1436
|
-
|
|
1437
|
-
{
|
|
1438
|
-
color: materialCost.active ? "green" : "grey",
|
|
1439
|
-
className: "cursor-pointer",
|
|
1440
|
-
onClick: () => handleToggleActive(materialCost),
|
|
1441
|
-
children: materialCost.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
|
|
1442
|
-
}
|
|
1443
|
-
) }),
|
|
1502
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: rate.price.toFixed(2) }),
|
|
1503
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: formatETA(rate) }) }),
|
|
1504
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
|
|
1444
1505
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
1445
1506
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1446
1507
|
ui.Button,
|
|
1447
1508
|
{
|
|
1448
1509
|
variant: "transparent",
|
|
1449
1510
|
size: "small",
|
|
1450
|
-
onClick: () => handleEdit(
|
|
1511
|
+
onClick: () => handleEdit(rate),
|
|
1451
1512
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
|
|
1452
1513
|
}
|
|
1453
1514
|
),
|
|
@@ -1456,38 +1517,25 @@ const MaterialCostsTable = () => {
|
|
|
1456
1517
|
{
|
|
1457
1518
|
variant: "transparent",
|
|
1458
1519
|
size: "small",
|
|
1459
|
-
onClick: () =>
|
|
1520
|
+
onClick: () => setDeleteRateId(rate.id),
|
|
1460
1521
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
|
|
1461
1522
|
}
|
|
1462
1523
|
)
|
|
1463
1524
|
] }) })
|
|
1464
|
-
] },
|
|
1525
|
+
] }, rate.id)) })
|
|
1465
1526
|
] })
|
|
1466
1527
|
] }),
|
|
1467
|
-
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1468
|
-
MaterialCostModal,
|
|
1469
|
-
{
|
|
1470
|
-
materialCost: editingMaterialCost,
|
|
1471
|
-
onClose: handleModalClose
|
|
1472
|
-
}
|
|
1473
|
-
),
|
|
1528
|
+
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ShippingRateModal, { rate: editingRate, onClose: handleModalClose }),
|
|
1474
1529
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1475
1530
|
ui.Prompt,
|
|
1476
1531
|
{
|
|
1477
1532
|
variant: "confirmation",
|
|
1478
|
-
open: !!
|
|
1479
|
-
onOpenChange: () =>
|
|
1480
|
-
setDeleteMaterialCostId(null);
|
|
1481
|
-
setDeleteMaterialCostName("");
|
|
1482
|
-
},
|
|
1533
|
+
open: !!deleteRateId,
|
|
1534
|
+
onOpenChange: () => setDeleteRateId(null),
|
|
1483
1535
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
|
|
1484
1536
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
|
|
1485
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "
|
|
1486
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1487
|
-
'คุณต้องการลบวัสดุ "',
|
|
1488
|
-
deleteMaterialCostName,
|
|
1489
|
-
'" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
|
|
1490
|
-
] })
|
|
1537
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบอัตราค่าขนส่ง" }),
|
|
1538
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: "คุณต้องการลบอัตราค่าขนส่งนี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
|
|
1491
1539
|
] }),
|
|
1492
1540
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [
|
|
1493
1541
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: "ยกเลิก" }),
|
|
@@ -1498,96 +1546,125 @@ const MaterialCostsTable = () => {
|
|
|
1498
1546
|
)
|
|
1499
1547
|
] });
|
|
1500
1548
|
};
|
|
1501
|
-
const
|
|
1549
|
+
const RatesPage = () => {
|
|
1502
1550
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
1503
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
1504
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1551
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "อัตราค่าขนส่ง" }) }),
|
|
1552
|
+
/* @__PURE__ */ jsxRuntime.jsx(ShippingRatesTable, {})
|
|
1505
1553
|
] }) });
|
|
1506
1554
|
};
|
|
1507
1555
|
const config$1 = adminSdk.defineRouteConfig({
|
|
1508
|
-
icon: icons.
|
|
1509
|
-
label: "
|
|
1556
|
+
icon: icons.HandTruck,
|
|
1557
|
+
label: "อัตราค่าขนส่ง"
|
|
1510
1558
|
});
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1559
|
+
const TH_PROVINCES = [
|
|
1560
|
+
"กรุงเทพมหานคร",
|
|
1561
|
+
"กระบี่",
|
|
1562
|
+
"กาญจนบุรี",
|
|
1563
|
+
"กาฬสินธุ์",
|
|
1564
|
+
"กำแพงเพชร",
|
|
1565
|
+
"ขอนแก่น",
|
|
1566
|
+
"จันทบุรี",
|
|
1567
|
+
"ฉะเชิงเทรา",
|
|
1568
|
+
"ชลบุรี",
|
|
1569
|
+
"ชัยนาท",
|
|
1570
|
+
"ชัยภูมิ",
|
|
1571
|
+
"ชุมพร",
|
|
1572
|
+
"เชียงราย",
|
|
1573
|
+
"เชียงใหม่",
|
|
1574
|
+
"ตรัง",
|
|
1575
|
+
"ตราด",
|
|
1576
|
+
"ตาก",
|
|
1577
|
+
"นครนายก",
|
|
1578
|
+
"นครปฐม",
|
|
1579
|
+
"นครพนม",
|
|
1580
|
+
"นครราชสีมา",
|
|
1581
|
+
"นครศรีธรรมราช",
|
|
1582
|
+
"นครสวรรค์",
|
|
1583
|
+
"นนทบุรี",
|
|
1584
|
+
"นราธิวาส",
|
|
1585
|
+
"น่าน",
|
|
1586
|
+
"บึงกาฬ",
|
|
1587
|
+
"บุรีรัมย์",
|
|
1588
|
+
"ปทุมธานี",
|
|
1589
|
+
"ประจวบคีรีขันธ์",
|
|
1590
|
+
"ปราจีนบุรี",
|
|
1591
|
+
"ปัตตานี",
|
|
1592
|
+
"พระนครศรีอยุธยา",
|
|
1593
|
+
"พะเยา",
|
|
1594
|
+
"พังงา",
|
|
1595
|
+
"พัทลุง",
|
|
1596
|
+
"พิจิตร",
|
|
1597
|
+
"พิษณุโลก",
|
|
1598
|
+
"เพชรบุรี",
|
|
1599
|
+
"เพชรบูรณ์",
|
|
1600
|
+
"แพร่",
|
|
1601
|
+
"ภูเก็ต",
|
|
1602
|
+
"มหาสารคาม",
|
|
1603
|
+
"มุกดาหาร",
|
|
1604
|
+
"แม่ฮ่องสอน",
|
|
1605
|
+
"ยโสธร",
|
|
1606
|
+
"ยะลา",
|
|
1607
|
+
"ร้อยเอ็ด",
|
|
1608
|
+
"ระนอง",
|
|
1609
|
+
"ระยอง",
|
|
1610
|
+
"ราชบุรี",
|
|
1611
|
+
"ลพบุรี",
|
|
1612
|
+
"ลำปาง",
|
|
1613
|
+
"ลำพูน",
|
|
1614
|
+
"เลย",
|
|
1615
|
+
"ศรีสะเกษ",
|
|
1616
|
+
"สกลนคร",
|
|
1617
|
+
"สงขลา",
|
|
1618
|
+
"สตูล",
|
|
1619
|
+
"สมุทรปราการ",
|
|
1620
|
+
"สมุทรสงคราม",
|
|
1621
|
+
"สมุทรสาคร",
|
|
1622
|
+
"สระแก้ว",
|
|
1623
|
+
"สระบุรี",
|
|
1624
|
+
"สิงห์บุรี",
|
|
1625
|
+
"สุโขทัย",
|
|
1626
|
+
"สุพรรณบุรี",
|
|
1627
|
+
"สุราษฎร์ธานี",
|
|
1628
|
+
"สุรินทร์",
|
|
1629
|
+
"หนองคาย",
|
|
1630
|
+
"หนองบัวลำภู",
|
|
1631
|
+
"อ่างทอง",
|
|
1632
|
+
"อำนาจเจริญ",
|
|
1633
|
+
"อุดรธานี",
|
|
1634
|
+
"อุตรดิตถ์",
|
|
1635
|
+
"อุทัยธานี",
|
|
1636
|
+
"อุบลราชธานี"
|
|
1521
1637
|
];
|
|
1522
|
-
const
|
|
1638
|
+
const ServiceAreaModal = ({ area, onClose }) => {
|
|
1523
1639
|
const [formData, setFormData] = react.useState({
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
max_weight_kg: "",
|
|
1527
|
-
price: "",
|
|
1528
|
-
currency: "THB",
|
|
1529
|
-
priority: "0",
|
|
1530
|
-
eta_hours_min: "",
|
|
1531
|
-
eta_hours_max: "",
|
|
1532
|
-
eta_days_min: "",
|
|
1533
|
-
eta_days_max: "",
|
|
1640
|
+
kind: "PROVINCE",
|
|
1641
|
+
value: "",
|
|
1534
1642
|
active: true
|
|
1535
1643
|
});
|
|
1536
1644
|
const [isSaving, setIsSaving] = react.useState(false);
|
|
1537
|
-
const selectedService = SERVICE_CODES$1.find((s) => s.value === formData.service_code);
|
|
1538
|
-
const usesHours = (selectedService == null ? void 0 : selectedService.usesHours) ?? false;
|
|
1539
1645
|
react.useEffect(() => {
|
|
1540
|
-
|
|
1541
|
-
if (rate) {
|
|
1646
|
+
if (area) {
|
|
1542
1647
|
setFormData({
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
price: rate.price.toString(),
|
|
1547
|
-
currency: rate.currency,
|
|
1548
|
-
priority: (rate.priority ?? 0).toString(),
|
|
1549
|
-
eta_hours_min: ((_a = rate.eta_hours_min) == null ? void 0 : _a.toString()) || "",
|
|
1550
|
-
eta_hours_max: ((_b = rate.eta_hours_max) == null ? void 0 : _b.toString()) || "",
|
|
1551
|
-
eta_days_min: ((_c = rate.eta_days_min) == null ? void 0 : _c.toString()) || "",
|
|
1552
|
-
eta_days_max: ((_d = rate.eta_days_max) == null ? void 0 : _d.toString()) || "",
|
|
1553
|
-
active: rate.active
|
|
1648
|
+
kind: area.kind,
|
|
1649
|
+
value: area.value,
|
|
1650
|
+
active: area.active
|
|
1554
1651
|
});
|
|
1555
1652
|
}
|
|
1556
|
-
}, [
|
|
1653
|
+
}, [area]);
|
|
1557
1654
|
const handleSubmit = async (e) => {
|
|
1558
1655
|
e.preventDefault();
|
|
1559
1656
|
const errors = [];
|
|
1560
|
-
const
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
if (isNaN(maxWeight) || maxWeight <= 0) {
|
|
1564
|
-
errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
|
|
1565
|
-
}
|
|
1566
|
-
if (isNaN(price) || price < 0) {
|
|
1567
|
-
errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
|
|
1568
|
-
}
|
|
1569
|
-
if (isNaN(priority)) {
|
|
1570
|
-
errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
|
|
1657
|
+
const trimmedValue = formData.value.trim();
|
|
1658
|
+
if (!trimmedValue) {
|
|
1659
|
+
errors.push("กรุณากรอกค่า");
|
|
1571
1660
|
}
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
let etaDaysMax;
|
|
1576
|
-
if (usesHours) {
|
|
1577
|
-
etaHoursMin = formData.eta_hours_min ? parseFloat(formData.eta_hours_min) : void 0;
|
|
1578
|
-
etaHoursMax = formData.eta_hours_max ? parseFloat(formData.eta_hours_max) : void 0;
|
|
1579
|
-
if (etaHoursMin === void 0 || etaHoursMax === void 0) {
|
|
1580
|
-
errors.push("กรุณากรอก ETA เป็นชั่วโมงให้ครบ");
|
|
1581
|
-
} else if (etaHoursMin > etaHoursMax) {
|
|
1582
|
-
errors.push("ETA ชั่วโมงต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
|
|
1661
|
+
if (formData.kind === "PROVINCE") {
|
|
1662
|
+
if (!TH_PROVINCES.includes(trimmedValue)) {
|
|
1663
|
+
errors.push("จังหวัดไม่ถูกต้อง กรุณาตรวจสอบการสะกดชื่อจังหวัด");
|
|
1583
1664
|
}
|
|
1584
|
-
} else {
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
if (etaDaysMin === void 0 || etaDaysMax === void 0) {
|
|
1588
|
-
errors.push("กรุณากรอก ETA เป็นวันให้ครบ");
|
|
1589
|
-
} else if (etaDaysMin > etaDaysMax) {
|
|
1590
|
-
errors.push("ETA วันต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
|
|
1665
|
+
} else if (formData.kind === "POSTCODE_PREFIX") {
|
|
1666
|
+
if (!/^\d{1,5}$/.test(trimmedValue)) {
|
|
1667
|
+
errors.push("รหัสไปรษณีย์ต้องเป็นตัวเลข 1-5 หลัก");
|
|
1591
1668
|
}
|
|
1592
1669
|
}
|
|
1593
1670
|
if (errors.length > 0) {
|
|
@@ -1599,23 +1676,12 @@ const ShippingRateModal = ({ rate, onClose }) => {
|
|
|
1599
1676
|
setIsSaving(true);
|
|
1600
1677
|
try {
|
|
1601
1678
|
const payload = {
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
max_weight_kg: maxWeight,
|
|
1605
|
-
price,
|
|
1606
|
-
currency: formData.currency,
|
|
1607
|
-
priority,
|
|
1679
|
+
kind: formData.kind,
|
|
1680
|
+
value: trimmedValue,
|
|
1608
1681
|
active: formData.active
|
|
1609
1682
|
};
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
payload.eta_hours_max = etaHoursMax;
|
|
1613
|
-
} else {
|
|
1614
|
-
payload.eta_days_min = etaDaysMin;
|
|
1615
|
-
payload.eta_days_max = etaDaysMax;
|
|
1616
|
-
}
|
|
1617
|
-
const url = rate ? `/admin/shipping-rates/${rate.id}` : "/admin/shipping-rates";
|
|
1618
|
-
const method = rate ? "PUT" : "POST";
|
|
1683
|
+
const url = area ? `/admin/service-areas/${area.id}` : "/admin/service-areas";
|
|
1684
|
+
const method = area ? "PUT" : "POST";
|
|
1619
1685
|
const response = await fetch(url, {
|
|
1620
1686
|
method,
|
|
1621
1687
|
headers: { "Content-Type": "application/json" },
|
|
@@ -1624,7 +1690,7 @@ const ShippingRateModal = ({ rate, onClose }) => {
|
|
|
1624
1690
|
});
|
|
1625
1691
|
if (response.ok) {
|
|
1626
1692
|
ui.toast.success("สำเร็จ", {
|
|
1627
|
-
description:
|
|
1693
|
+
description: area ? "แก้ไขพื้นที่บริการแล้ว" : "สร้างพื้นที่บริการใหม่แล้ว"
|
|
1628
1694
|
});
|
|
1629
1695
|
onClose();
|
|
1630
1696
|
} else {
|
|
@@ -1640,139 +1706,53 @@ const ShippingRateModal = ({ rate, onClose }) => {
|
|
|
1640
1706
|
}
|
|
1641
1707
|
};
|
|
1642
1708
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
1643
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children:
|
|
1709
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: area ? "แก้ไขพื้นที่บริการ" : "สร้างพื้นที่บริการใหม่" }) }),
|
|
1644
1710
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
|
|
1645
1711
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1646
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1712
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "kind", children: "ประเภท *" }),
|
|
1647
1713
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1648
1714
|
ui.Select,
|
|
1649
1715
|
{
|
|
1650
|
-
value: formData.
|
|
1651
|
-
onValueChange: (value) => setFormData({ ...formData,
|
|
1716
|
+
value: formData.kind,
|
|
1717
|
+
onValueChange: (value) => setFormData({ ...formData, kind: value, value: "" }),
|
|
1718
|
+
required: true,
|
|
1652
1719
|
children: [
|
|
1653
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "
|
|
1654
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1720
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกประเภท" }) }),
|
|
1721
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select.Content, { children: [
|
|
1722
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "PROVINCE", children: "จังหวัด" }),
|
|
1723
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: "POSTCODE_PREFIX", children: "รหัสไปรษณีย์" })
|
|
1724
|
+
] })
|
|
1655
1725
|
]
|
|
1656
1726
|
}
|
|
1657
1727
|
)
|
|
1658
1728
|
] }),
|
|
1659
1729
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1660
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "
|
|
1661
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1730
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "value", children: formData.kind === "PROVINCE" ? "ชื่อจังหวัด *" : "รหัสไปรษณีย์ (1-5 หลัก) *" }),
|
|
1731
|
+
formData.kind === "PROVINCE" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1662
1732
|
ui.Select,
|
|
1663
1733
|
{
|
|
1664
|
-
value: formData.
|
|
1665
|
-
onValueChange: (value) => setFormData({
|
|
1666
|
-
|
|
1667
|
-
service_code: value,
|
|
1668
|
-
eta_hours_min: "",
|
|
1669
|
-
eta_hours_max: "",
|
|
1670
|
-
eta_days_min: "",
|
|
1671
|
-
eta_days_max: ""
|
|
1672
|
-
}),
|
|
1734
|
+
value: formData.value,
|
|
1735
|
+
onValueChange: (value) => setFormData({ ...formData, value }),
|
|
1736
|
+
required: true,
|
|
1673
1737
|
children: [
|
|
1674
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "
|
|
1675
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children:
|
|
1738
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกจังหวัด" }) }),
|
|
1739
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: TH_PROVINCES.map((province) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: province, children: province }, province)) })
|
|
1676
1740
|
]
|
|
1677
1741
|
}
|
|
1678
|
-
)
|
|
1679
|
-
] }),
|
|
1680
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
|
|
1681
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1682
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
|
|
1683
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1684
|
-
ui.Input,
|
|
1685
|
-
{
|
|
1686
|
-
id: "maxWeight",
|
|
1687
|
-
type: "number",
|
|
1688
|
-
step: "0.1",
|
|
1689
|
-
min: "0",
|
|
1690
|
-
value: formData.max_weight_kg,
|
|
1691
|
-
onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
|
|
1692
|
-
placeholder: "เช่น 3",
|
|
1693
|
-
required: true
|
|
1694
|
-
}
|
|
1695
|
-
)
|
|
1696
|
-
] }),
|
|
1697
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1698
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
|
|
1699
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1700
|
-
ui.Input,
|
|
1701
|
-
{
|
|
1702
|
-
id: "price",
|
|
1703
|
-
type: "number",
|
|
1704
|
-
step: "0.01",
|
|
1705
|
-
min: "0",
|
|
1706
|
-
value: formData.price,
|
|
1707
|
-
onChange: (e) => setFormData({ ...formData, price: e.target.value }),
|
|
1708
|
-
placeholder: "เช่น 80",
|
|
1709
|
-
required: true
|
|
1710
|
-
}
|
|
1711
|
-
)
|
|
1712
|
-
] })
|
|
1713
|
-
] }),
|
|
1714
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1715
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
|
|
1716
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1742
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1717
1743
|
ui.Input,
|
|
1718
1744
|
{
|
|
1719
|
-
id: "
|
|
1720
|
-
type: "
|
|
1721
|
-
value: formData.
|
|
1722
|
-
onChange: (e) => setFormData({ ...formData,
|
|
1723
|
-
placeholder: "
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1730
|
-
usesHours ? "ETA (ชั่วโมง)" : "ETA (วัน)",
|
|
1731
|
-
" *"
|
|
1732
|
-
] }),
|
|
1733
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 mt-2", children: usesHours ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1734
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1735
|
-
ui.Input,
|
|
1736
|
-
{
|
|
1737
|
-
type: "number",
|
|
1738
|
-
placeholder: "ต่ำสุด",
|
|
1739
|
-
value: formData.eta_hours_min,
|
|
1740
|
-
onChange: (e) => setFormData({ ...formData, eta_hours_min: e.target.value }),
|
|
1741
|
-
required: true
|
|
1742
|
-
}
|
|
1743
|
-
),
|
|
1744
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1745
|
-
ui.Input,
|
|
1746
|
-
{
|
|
1747
|
-
type: "number",
|
|
1748
|
-
placeholder: "สูงสุด",
|
|
1749
|
-
value: formData.eta_hours_max,
|
|
1750
|
-
onChange: (e) => setFormData({ ...formData, eta_hours_max: e.target.value }),
|
|
1751
|
-
required: true
|
|
1752
|
-
}
|
|
1753
|
-
)
|
|
1754
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1755
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1756
|
-
ui.Input,
|
|
1757
|
-
{
|
|
1758
|
-
type: "number",
|
|
1759
|
-
placeholder: "ต่ำสุด",
|
|
1760
|
-
value: formData.eta_days_min,
|
|
1761
|
-
onChange: (e) => setFormData({ ...formData, eta_days_min: e.target.value }),
|
|
1762
|
-
required: true
|
|
1763
|
-
}
|
|
1764
|
-
),
|
|
1765
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1766
|
-
ui.Input,
|
|
1767
|
-
{
|
|
1768
|
-
type: "number",
|
|
1769
|
-
placeholder: "สูงสุด",
|
|
1770
|
-
value: formData.eta_days_max,
|
|
1771
|
-
onChange: (e) => setFormData({ ...formData, eta_days_max: e.target.value }),
|
|
1772
|
-
required: true
|
|
1773
|
-
}
|
|
1774
|
-
)
|
|
1775
|
-
] }) })
|
|
1745
|
+
id: "value",
|
|
1746
|
+
type: "text",
|
|
1747
|
+
value: formData.value,
|
|
1748
|
+
onChange: (e) => setFormData({ ...formData, value: e.target.value }),
|
|
1749
|
+
placeholder: "เช่น 10, 102, 10200",
|
|
1750
|
+
maxLength: 5,
|
|
1751
|
+
pattern: "\\d{1,5}",
|
|
1752
|
+
required: true
|
|
1753
|
+
}
|
|
1754
|
+
),
|
|
1755
|
+
formData.kind === "POSTCODE_PREFIX" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: 'ใส่รหัส 1-5 หลักเพื่อครอบคลุมหลายพื้นที่ เช่น "10" = กรุงเทพฯ ทั้งหมด' })
|
|
1776
1756
|
] }),
|
|
1777
1757
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
1778
1758
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1786,168 +1766,181 @@ const ShippingRateModal = ({ rate, onClose }) => {
|
|
|
1786
1766
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
|
|
1787
1767
|
] }),
|
|
1788
1768
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
1789
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1769
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1770
|
+
ui.Button,
|
|
1771
|
+
{
|
|
1772
|
+
type: "button",
|
|
1773
|
+
variant: "secondary",
|
|
1774
|
+
onClick: onClose,
|
|
1775
|
+
disabled: isSaving,
|
|
1776
|
+
children: "ยกเลิก"
|
|
1777
|
+
}
|
|
1778
|
+
),
|
|
1790
1779
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
|
|
1791
1780
|
] })
|
|
1792
1781
|
] }) })
|
|
1793
1782
|
] }) });
|
|
1794
1783
|
};
|
|
1795
|
-
const
|
|
1796
|
-
{ value: "ALL", label: "ทั้งหมด" },
|
|
1797
|
-
{ value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
|
|
1798
|
-
{ value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
|
|
1799
|
-
{ value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
|
|
1800
|
-
];
|
|
1801
|
-
const SERVICE_CODES = [
|
|
1784
|
+
const AREA_KINDS = [
|
|
1802
1785
|
{ value: "ALL", label: "ทั้งหมด" },
|
|
1803
|
-
{ value: "
|
|
1804
|
-
{ value: "
|
|
1805
|
-
{ value: "STANDARD_3_5D", label: "EMS 3-5 วัน" },
|
|
1806
|
-
{ value: "EXPRESS_1_2D", label: "Express 1-2 วัน" }
|
|
1786
|
+
{ value: "PROVINCE", label: "จังหวัด" },
|
|
1787
|
+
{ value: "POSTCODE_PREFIX", label: "รหัสไปรษณีย์" }
|
|
1807
1788
|
];
|
|
1808
|
-
const
|
|
1809
|
-
const [
|
|
1810
|
-
const [
|
|
1811
|
-
const [
|
|
1812
|
-
const [
|
|
1789
|
+
const ServiceAreasTable = () => {
|
|
1790
|
+
const [areas, setAreas] = react.useState([]);
|
|
1791
|
+
const [filteredAreas, setFilteredAreas] = react.useState([]);
|
|
1792
|
+
const [searchTerm, setSearchTerm] = react.useState("");
|
|
1793
|
+
const [kindFilter, setKindFilter] = react.useState("ALL");
|
|
1813
1794
|
const [isModalOpen, setIsModalOpen] = react.useState(false);
|
|
1814
|
-
const [
|
|
1795
|
+
const [editingArea, setEditingArea] = react.useState(null);
|
|
1815
1796
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
1816
|
-
const [
|
|
1797
|
+
const [deleteAreaId, setDeleteAreaId] = react.useState(null);
|
|
1798
|
+
const [deleteAreaValue, setDeleteAreaValue] = react.useState("");
|
|
1817
1799
|
react.useEffect(() => {
|
|
1818
|
-
|
|
1800
|
+
fetchAreas();
|
|
1819
1801
|
}, []);
|
|
1820
1802
|
react.useEffect(() => {
|
|
1821
|
-
let filtered =
|
|
1822
|
-
if (
|
|
1823
|
-
filtered = filtered.filter((
|
|
1803
|
+
let filtered = areas;
|
|
1804
|
+
if (kindFilter !== "ALL") {
|
|
1805
|
+
filtered = filtered.filter((area) => area.kind === kindFilter);
|
|
1824
1806
|
}
|
|
1825
|
-
if (
|
|
1826
|
-
filtered = filtered.filter(
|
|
1807
|
+
if (searchTerm) {
|
|
1808
|
+
filtered = filtered.filter(
|
|
1809
|
+
(area) => area.value.toLowerCase().includes(searchTerm.toLowerCase())
|
|
1810
|
+
);
|
|
1827
1811
|
}
|
|
1828
|
-
|
|
1829
|
-
}, [
|
|
1830
|
-
const
|
|
1812
|
+
setFilteredAreas(filtered);
|
|
1813
|
+
}, [searchTerm, kindFilter, areas]);
|
|
1814
|
+
const fetchAreas = async () => {
|
|
1831
1815
|
setIsLoading(true);
|
|
1832
1816
|
try {
|
|
1833
|
-
const response = await fetch("/admin/
|
|
1817
|
+
const response = await fetch("/admin/service-areas", {
|
|
1834
1818
|
credentials: "include"
|
|
1835
1819
|
});
|
|
1836
1820
|
const data = await response.json();
|
|
1837
|
-
|
|
1821
|
+
console.log("Fetched service areas:", data);
|
|
1822
|
+
setAreas(data.service_areas || []);
|
|
1838
1823
|
} catch (error) {
|
|
1839
1824
|
ui.toast.error("ข้อผิดพลาด", {
|
|
1840
|
-
description: "
|
|
1825
|
+
description: "ไม่สามารถโหลดข้อมูลพื้นที่บริการได้"
|
|
1841
1826
|
});
|
|
1842
1827
|
} finally {
|
|
1843
1828
|
setIsLoading(false);
|
|
1844
1829
|
}
|
|
1845
1830
|
};
|
|
1831
|
+
const handleToggleActive = async (area) => {
|
|
1832
|
+
try {
|
|
1833
|
+
const response = await fetch(`/admin/service-areas/${area.id}`, {
|
|
1834
|
+
method: "PUT",
|
|
1835
|
+
headers: { "Content-Type": "application/json" },
|
|
1836
|
+
credentials: "include",
|
|
1837
|
+
body: JSON.stringify({ ...area, active: !area.active })
|
|
1838
|
+
});
|
|
1839
|
+
if (response.ok) {
|
|
1840
|
+
ui.toast.success("สำเร็จ", {
|
|
1841
|
+
description: `${area.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}พื้นที่ ${area.value} แล้ว`
|
|
1842
|
+
});
|
|
1843
|
+
fetchAreas();
|
|
1844
|
+
} else {
|
|
1845
|
+
throw new Error("Failed to update");
|
|
1846
|
+
}
|
|
1847
|
+
} catch (error) {
|
|
1848
|
+
ui.toast.error("ข้อผิดพลาด", {
|
|
1849
|
+
description: "ไม่สามารถอัพเดทสถานะได้"
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
};
|
|
1846
1853
|
const handleDelete = async () => {
|
|
1847
|
-
if (!
|
|
1854
|
+
if (!deleteAreaId) return;
|
|
1848
1855
|
try {
|
|
1849
|
-
const response = await fetch(`/admin/
|
|
1856
|
+
const response = await fetch(`/admin/service-areas/${deleteAreaId}`, {
|
|
1850
1857
|
method: "DELETE",
|
|
1851
1858
|
credentials: "include"
|
|
1852
1859
|
});
|
|
1853
1860
|
if (response.ok) {
|
|
1854
1861
|
ui.toast.success("สำเร็จ", {
|
|
1855
|
-
description:
|
|
1862
|
+
description: `ลบพื้นที่ ${deleteAreaValue} แล้ว`
|
|
1856
1863
|
});
|
|
1857
|
-
|
|
1864
|
+
fetchAreas();
|
|
1858
1865
|
} else {
|
|
1859
1866
|
throw new Error("Failed to delete");
|
|
1860
1867
|
}
|
|
1861
1868
|
} catch (error) {
|
|
1862
1869
|
ui.toast.error("ข้อผิดพลาด", {
|
|
1863
|
-
description: "
|
|
1870
|
+
description: "ไม่สามารถลบพื้นที่ได้"
|
|
1864
1871
|
});
|
|
1865
1872
|
} finally {
|
|
1866
|
-
|
|
1873
|
+
setDeleteAreaId(null);
|
|
1874
|
+
setDeleteAreaValue("");
|
|
1867
1875
|
}
|
|
1868
1876
|
};
|
|
1869
|
-
const handleEdit = (
|
|
1870
|
-
|
|
1877
|
+
const handleEdit = (area) => {
|
|
1878
|
+
setEditingArea(area);
|
|
1871
1879
|
setIsModalOpen(true);
|
|
1872
1880
|
};
|
|
1873
1881
|
const handleCreateNew = () => {
|
|
1874
|
-
|
|
1882
|
+
setEditingArea(null);
|
|
1875
1883
|
setIsModalOpen(true);
|
|
1876
1884
|
};
|
|
1877
1885
|
const handleModalClose = () => {
|
|
1878
1886
|
setIsModalOpen(false);
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
};
|
|
1882
|
-
const getCarrierLabel = (type) => {
|
|
1883
|
-
var _a;
|
|
1884
|
-
return ((_a = CARRIER_TYPES.find((c) => c.value === type)) == null ? void 0 : _a.label) || type;
|
|
1885
|
-
};
|
|
1886
|
-
const getServiceLabel = (code) => {
|
|
1887
|
-
var _a;
|
|
1888
|
-
return ((_a = SERVICE_CODES.find((s) => s.value === code)) == null ? void 0 : _a.label) || code;
|
|
1887
|
+
setEditingArea(null);
|
|
1888
|
+
fetchAreas();
|
|
1889
1889
|
};
|
|
1890
|
-
const
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
}
|
|
1894
|
-
if (rate.eta_days_min !== null && rate.eta_days_min !== void 0 && rate.eta_days_max !== null && rate.eta_days_max !== void 0) {
|
|
1895
|
-
return `${rate.eta_days_min}-${rate.eta_days_max} วัน`;
|
|
1896
|
-
}
|
|
1897
|
-
return "-";
|
|
1890
|
+
const openDeletePrompt = (id, value) => {
|
|
1891
|
+
setDeleteAreaId(id);
|
|
1892
|
+
setDeleteAreaValue(value);
|
|
1898
1893
|
};
|
|
1899
1894
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1900
1895
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
1901
1896
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
|
|
1902
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4
|
|
1903
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1897
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 flex-1", children: [
|
|
1898
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1899
|
+
ui.Input,
|
|
1900
|
+
{
|
|
1901
|
+
type: "search",
|
|
1902
|
+
placeholder: "ค้นหาจังหวัดหรือรหัสไปรษณีย์...",
|
|
1903
|
+
value: searchTerm,
|
|
1904
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
1905
|
+
className: "max-w-md"
|
|
1906
|
+
}
|
|
1907
|
+
),
|
|
1908
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: kindFilter, onValueChange: setKindFilter, children: [
|
|
1909
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ประเภท" }) }),
|
|
1910
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: AREA_KINDS.map((kind) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: kind.value, children: kind.label }, kind.value)) })
|
|
1916
1911
|
] })
|
|
1917
1912
|
] }),
|
|
1918
1913
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
|
|
1919
1914
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
|
|
1920
|
-
"
|
|
1915
|
+
"สร้างพื้นที่ใหม่"
|
|
1921
1916
|
] })
|
|
1922
1917
|
] }),
|
|
1923
1918
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
|
|
1924
1919
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
1925
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1926
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "
|
|
1927
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "น้ำหนัก ≤ (kg)" }),
|
|
1928
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
|
|
1929
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ETA" }),
|
|
1920
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ประเภท" }),
|
|
1921
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ค่า" }),
|
|
1930
1922
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
|
|
1931
1923
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
|
|
1932
1924
|
] }) }),
|
|
1933
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) :
|
|
1934
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
1935
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children:
|
|
1936
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1925
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredAreas.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลพื้นที่บริการ" }) }) : filteredAreas.map((area) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
|
|
1926
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: area.kind === "PROVINCE" ? "blue" : "purple", children: area.kind === "PROVINCE" ? "จังหวัด" : "รหัสไปรษณีย์" }) }),
|
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: area.value }),
|
|
1928
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1929
|
+
ui.Badge,
|
|
1930
|
+
{
|
|
1931
|
+
color: area.active ? "green" : "grey",
|
|
1932
|
+
className: "cursor-pointer",
|
|
1933
|
+
onClick: () => handleToggleActive(area),
|
|
1934
|
+
children: area.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
|
|
1935
|
+
}
|
|
1936
|
+
) }),
|
|
1944
1937
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
|
|
1945
1938
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1946
1939
|
ui.Button,
|
|
1947
1940
|
{
|
|
1948
1941
|
variant: "transparent",
|
|
1949
1942
|
size: "small",
|
|
1950
|
-
onClick: () => handleEdit(
|
|
1943
|
+
onClick: () => handleEdit(area),
|
|
1951
1944
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
|
|
1952
1945
|
}
|
|
1953
1946
|
),
|
|
@@ -1956,25 +1949,32 @@ const ShippingRatesTable = () => {
|
|
|
1956
1949
|
{
|
|
1957
1950
|
variant: "transparent",
|
|
1958
1951
|
size: "small",
|
|
1959
|
-
onClick: () =>
|
|
1952
|
+
onClick: () => openDeletePrompt(area.id, area.value),
|
|
1960
1953
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
|
|
1961
1954
|
}
|
|
1962
1955
|
)
|
|
1963
1956
|
] }) })
|
|
1964
|
-
] },
|
|
1957
|
+
] }, area.id)) })
|
|
1965
1958
|
] })
|
|
1966
1959
|
] }),
|
|
1967
|
-
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1960
|
+
isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ServiceAreaModal, { area: editingArea, onClose: handleModalClose }),
|
|
1968
1961
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1969
1962
|
ui.Prompt,
|
|
1970
1963
|
{
|
|
1971
1964
|
variant: "confirmation",
|
|
1972
|
-
open: !!
|
|
1973
|
-
onOpenChange: () =>
|
|
1965
|
+
open: !!deleteAreaId,
|
|
1966
|
+
onOpenChange: () => {
|
|
1967
|
+
setDeleteAreaId(null);
|
|
1968
|
+
setDeleteAreaValue("");
|
|
1969
|
+
},
|
|
1974
1970
|
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
|
|
1975
1971
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
|
|
1976
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "
|
|
1977
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1972
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบพื้นที่บริการ" }),
|
|
1973
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Description, { children: [
|
|
1974
|
+
'คุณต้องการลบพื้นที่ "',
|
|
1975
|
+
deleteAreaValue,
|
|
1976
|
+
'" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
|
|
1977
|
+
] })
|
|
1978
1978
|
] }),
|
|
1979
1979
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [
|
|
1980
1980
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: "ยกเลิก" }),
|
|
@@ -1985,15 +1985,15 @@ const ShippingRatesTable = () => {
|
|
|
1985
1985
|
)
|
|
1986
1986
|
] });
|
|
1987
1987
|
};
|
|
1988
|
-
const
|
|
1988
|
+
const AreasPage = () => {
|
|
1989
1989
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
|
|
1990
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "
|
|
1991
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1990
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "พื้นที่บริการ" }) }),
|
|
1991
|
+
/* @__PURE__ */ jsxRuntime.jsx(ServiceAreasTable, {})
|
|
1992
1992
|
] }) });
|
|
1993
1993
|
};
|
|
1994
1994
|
const config = adminSdk.defineRouteConfig({
|
|
1995
|
-
icon: icons.
|
|
1996
|
-
label: "
|
|
1995
|
+
icon: icons.MapPin,
|
|
1996
|
+
label: "พื้นที่บริการ"
|
|
1997
1997
|
});
|
|
1998
1998
|
const widgetModule = { widgets: [
|
|
1999
1999
|
{
|
|
@@ -2003,10 +2003,6 @@ const widgetModule = { widgets: [
|
|
|
2003
2003
|
] };
|
|
2004
2004
|
const routeModule = {
|
|
2005
2005
|
routes: [
|
|
2006
|
-
{
|
|
2007
|
-
Component: AreasPage,
|
|
2008
|
-
path: "/areas"
|
|
2009
|
-
},
|
|
2010
2006
|
{
|
|
2011
2007
|
Component: BoxesPage,
|
|
2012
2008
|
path: "/boxes"
|
|
@@ -2018,32 +2014,36 @@ const routeModule = {
|
|
|
2018
2014
|
{
|
|
2019
2015
|
Component: RatesPage,
|
|
2020
2016
|
path: "/rates"
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
Component: AreasPage,
|
|
2020
|
+
path: "/areas"
|
|
2021
2021
|
}
|
|
2022
2022
|
]
|
|
2023
2023
|
};
|
|
2024
2024
|
const menuItemModule = {
|
|
2025
2025
|
menuItems: [
|
|
2026
2026
|
{
|
|
2027
|
-
label: config
|
|
2028
|
-
icon: config
|
|
2027
|
+
label: config.label,
|
|
2028
|
+
icon: config.icon,
|
|
2029
2029
|
path: "/areas",
|
|
2030
2030
|
nested: void 0
|
|
2031
2031
|
},
|
|
2032
2032
|
{
|
|
2033
|
-
label: config$
|
|
2034
|
-
icon: config$
|
|
2033
|
+
label: config$3.label,
|
|
2034
|
+
icon: config$3.icon,
|
|
2035
2035
|
path: "/boxes",
|
|
2036
2036
|
nested: void 0
|
|
2037
2037
|
},
|
|
2038
2038
|
{
|
|
2039
|
-
label: config$
|
|
2040
|
-
icon: config$
|
|
2039
|
+
label: config$2.label,
|
|
2040
|
+
icon: config$2.icon,
|
|
2041
2041
|
path: "/material-costs",
|
|
2042
2042
|
nested: void 0
|
|
2043
2043
|
},
|
|
2044
2044
|
{
|
|
2045
|
-
label: config.label,
|
|
2046
|
-
icon: config.icon,
|
|
2045
|
+
label: config$1.label,
|
|
2046
|
+
icon: config$1.icon,
|
|
2047
2047
|
path: "/rates",
|
|
2048
2048
|
nested: void 0
|
|
2049
2049
|
}
|