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