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