@lodashventure/medusa-parcel-shipping 0.4.31 → 0.4.34

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.
@@ -1427,88 +1427,53 @@ const config$2 = adminSdk.defineRouteConfig({
1427
1427
  icon: icons.ArchiveBox,
1428
1428
  label: "กล่องพัสดุ"
1429
1429
  });
1430
- const CARRIER_TYPES$1 = [
1431
- { value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
1432
- { value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
1433
- { value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
1434
- ];
1435
- const SERVICE_CODES$1 = [
1436
- { value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม.", usesHours: true },
1437
- { value: "SAME_DAY", label: "ส่งด่วนภายในวัน", usesHours: true },
1438
- { value: "STANDARD_3_5D", label: "EMS 3-5 วัน", usesHours: false },
1439
- { value: "EXPRESS_1_2D", label: "Express 1-2 วัน", usesHours: false }
1430
+ const CATEGORIES$1 = [
1431
+ { value: "PACKAGING", label: "วัสดุหีบห่อ" },
1432
+ { value: "PROTECTION", label: "วัสดุป้องกัน" },
1433
+ { value: "FILLING", label: "วัสดุเติมช่องว่าง" },
1434
+ { value: "TAPE", label: "เทป/กาว" },
1435
+ { value: "LABEL", label: "ฉลาก/สติกเกอร์" },
1436
+ { value: "OTHER", label: "อื่นๆ" }
1440
1437
  ];
1441
- const ShippingRateModal = ({ rate, onClose }) => {
1438
+ const MaterialCostModal = ({
1439
+ materialCost,
1440
+ onClose
1441
+ }) => {
1442
1442
  const [formData, setFormData] = react.useState({
1443
- carrier_type: "COMPANY_FLEET",
1444
- service_code: "MESSENGER_3H",
1445
- max_weight_kg: "",
1446
- price: "",
1443
+ name: "",
1444
+ unit: "",
1445
+ cost_per_unit: "",
1447
1446
  currency: "THB",
1448
- priority: "0",
1449
- eta_hours_min: "",
1450
- eta_hours_max: "",
1451
- eta_days_min: "",
1452
- eta_days_max: "",
1447
+ category: "",
1448
+ description: "",
1453
1449
  active: true
1454
1450
  });
1455
1451
  const [isSaving, setIsSaving] = react.useState(false);
1456
- const selectedService = SERVICE_CODES$1.find((s) => s.value === formData.service_code);
1457
- const usesHours = (selectedService == null ? void 0 : selectedService.usesHours) ?? false;
1458
- const isMessenger = formData.carrier_type === "COMPANY_FLEET" && formData.service_code === "MESSENGER_3H";
1459
1452
  react.useEffect(() => {
1460
- var _a, _b, _c, _d;
1461
- if (rate) {
1453
+ if (materialCost) {
1462
1454
  setFormData({
1463
- carrier_type: rate.carrier_type,
1464
- service_code: rate.service_code,
1465
- max_weight_kg: rate.max_weight_kg.toString(),
1466
- price: rate.price.toString(),
1467
- currency: rate.currency,
1468
- priority: (rate.priority ?? 0).toString(),
1469
- eta_hours_min: ((_a = rate.eta_hours_min) == null ? void 0 : _a.toString()) || "",
1470
- eta_hours_max: ((_b = rate.eta_hours_max) == null ? void 0 : _b.toString()) || "",
1471
- eta_days_min: ((_c = rate.eta_days_min) == null ? void 0 : _c.toString()) || "",
1472
- eta_days_max: ((_d = rate.eta_days_max) == null ? void 0 : _d.toString()) || "",
1473
- active: rate.active
1455
+ name: materialCost.name,
1456
+ unit: materialCost.unit,
1457
+ cost_per_unit: materialCost.cost_per_unit.toString(),
1458
+ currency: materialCost.currency,
1459
+ category: materialCost.category || "",
1460
+ description: materialCost.description || "",
1461
+ active: materialCost.active
1474
1462
  });
1475
1463
  }
1476
- }, [rate]);
1464
+ }, [materialCost]);
1477
1465
  const handleSubmit = async (e) => {
1478
1466
  e.preventDefault();
1479
1467
  const errors = [];
1480
- const maxWeight = parseFloat(formData.max_weight_kg);
1481
- const price = parseFloat(formData.price);
1482
- const priority = parseInt(formData.priority);
1483
- if (isNaN(maxWeight) || maxWeight <= 0) {
1484
- errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
1485
- }
1486
- if (isNaN(price) || price < 0) {
1487
- errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
1468
+ if (!formData.name.trim()) {
1469
+ errors.push("กรุณากรอกชื่อวัสดุ");
1488
1470
  }
1489
- if (isNaN(priority)) {
1490
- errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
1471
+ if (!formData.unit.trim()) {
1472
+ errors.push("กรุณากรอกหน่วย");
1491
1473
  }
1492
- let etaHoursMin;
1493
- let etaHoursMax;
1494
- let etaDaysMin;
1495
- let etaDaysMax;
1496
- if (usesHours) {
1497
- etaHoursMin = formData.eta_hours_min ? parseFloat(formData.eta_hours_min) : void 0;
1498
- etaHoursMax = formData.eta_hours_max ? parseFloat(formData.eta_hours_max) : void 0;
1499
- if (etaHoursMin === void 0 || etaHoursMax === void 0) {
1500
- errors.push("กรุณากรอก ETA เป็นชั่วโมงให้ครบ");
1501
- } else if (etaHoursMin > etaHoursMax) {
1502
- errors.push("ETA ชั่วโมงต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
1503
- }
1504
- } else {
1505
- etaDaysMin = formData.eta_days_min ? parseFloat(formData.eta_days_min) : void 0;
1506
- etaDaysMax = formData.eta_days_max ? parseFloat(formData.eta_days_max) : void 0;
1507
- if (etaDaysMin === void 0 || etaDaysMax === void 0) {
1508
- errors.push("กรุณากรอก ETA เป็นวันให้ครบ");
1509
- } else if (etaDaysMin > etaDaysMax) {
1510
- errors.push("ETA วันต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
1511
- }
1474
+ const costPerUnit = parseFloat(formData.cost_per_unit);
1475
+ if (isNaN(costPerUnit) || costPerUnit < 0) {
1476
+ errors.push("ต้นทุนต่อหน่วยต้องเป็นตัวเลขไม่ติดลบ");
1512
1477
  }
1513
1478
  if (errors.length > 0) {
1514
1479
  ui.toast.error("ข้อมูลไม่ถูกต้อง", {
@@ -1519,23 +1484,16 @@ const ShippingRateModal = ({ rate, onClose }) => {
1519
1484
  setIsSaving(true);
1520
1485
  try {
1521
1486
  const payload = {
1522
- carrier_type: formData.carrier_type,
1523
- service_code: formData.service_code,
1524
- max_weight_kg: maxWeight,
1525
- price,
1487
+ name: formData.name.trim(),
1488
+ unit: formData.unit.trim(),
1489
+ cost_per_unit: costPerUnit,
1526
1490
  currency: formData.currency,
1527
- priority,
1491
+ category: formData.category || void 0,
1492
+ description: formData.description.trim() || void 0,
1528
1493
  active: formData.active
1529
1494
  };
1530
- if (usesHours) {
1531
- payload.eta_hours_min = etaHoursMin;
1532
- payload.eta_hours_max = etaHoursMax;
1533
- } else {
1534
- payload.eta_days_min = etaDaysMin;
1535
- payload.eta_days_max = etaDaysMax;
1536
- }
1537
- const url = rate ? `/admin/shipping-rates/${rate.id}` : "/admin/shipping-rates";
1538
- const method = rate ? "PUT" : "POST";
1495
+ const url = materialCost ? `/admin/material-costs/${materialCost.id}` : "/admin/material-costs";
1496
+ const method = materialCost ? "PUT" : "POST";
1539
1497
  const response = await fetch(url, {
1540
1498
  method,
1541
1499
  headers: { "Content-Type": "application/json" },
@@ -1544,7 +1502,7 @@ const ShippingRateModal = ({ rate, onClose }) => {
1544
1502
  });
1545
1503
  if (response.ok) {
1546
1504
  ui.toast.success("สำเร็จ", {
1547
- description: rate ? "แก้ไขอัตราค่าขนส่งแล้ว" : "สร้างอัตราค่าขนส่งใหม่แล้ว"
1505
+ description: materialCost ? "แก้ไขรายการต้นทุนวัสดุแล้ว" : "สร้างรายการต้นทุนวัสดุใหม่แล้ว"
1548
1506
  });
1549
1507
  onClose();
1550
1508
  } else {
@@ -1560,151 +1518,93 @@ const ShippingRateModal = ({ rate, onClose }) => {
1560
1518
  }
1561
1519
  };
1562
1520
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
1563
- /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: rate ? "แก้ไขอัตราค่าขนส่ง" : "สร้างอัตราค่าขนส่งใหม่" }) }),
1521
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: materialCost ? "แก้ไขรายการต้นทุนวัสดุ" : "สร้างรายการต้นทุนวัสดุใหม่" }) }),
1564
1522
  /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
1565
1523
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1566
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "carrier", children: "ประเภทขนส่ง *" }),
1567
- /* @__PURE__ */ jsxRuntime.jsxs(
1568
- ui.Select,
1524
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "name", children: "ชื่อวัสดุ *" }),
1525
+ /* @__PURE__ */ jsxRuntime.jsx(
1526
+ ui.Input,
1569
1527
  {
1570
- value: formData.carrier_type,
1571
- onValueChange: (value) => setFormData({ ...formData, carrier_type: value }),
1572
- children: [
1573
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกประเภทขนส่ง" }) }),
1574
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES$1.map((carrier) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: carrier.value, children: carrier.label }, carrier.value)) })
1575
- ]
1528
+ id: "name",
1529
+ value: formData.name,
1530
+ onChange: (e) => setFormData({ ...formData, name: e.target.value }),
1531
+ placeholder: "เช่น พลาสติกกันกระแทก, กล่องกระดาษ",
1532
+ required: true
1576
1533
  }
1577
1534
  )
1578
1535
  ] }),
1579
1536
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1580
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "service", children: "บริการจัดส่ง *" }),
1537
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "category", children: "หมวดหมู่ (ไม่บังคับ)" }),
1581
1538
  /* @__PURE__ */ jsxRuntime.jsxs(
1582
1539
  ui.Select,
1583
1540
  {
1584
- value: formData.service_code,
1585
- onValueChange: (value) => setFormData({
1586
- ...formData,
1587
- service_code: value,
1588
- eta_hours_min: "",
1589
- eta_hours_max: "",
1590
- eta_days_min: "",
1591
- eta_days_max: ""
1592
- }),
1541
+ value: formData.category || void 0,
1542
+ onValueChange: (value) => setFormData({ ...formData, category: value }),
1593
1543
  children: [
1594
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกบริการ" }) }),
1595
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES$1.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
1544
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกหมวดหมู่ (ไม่บังคับ)" }) }),
1545
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES$1.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
1596
1546
  ]
1597
1547
  }
1598
1548
  )
1599
1549
  ] }),
1600
- isMessenger && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 text-sm space-y-1", children: [
1601
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-ui-fg-base", children: "ฐานราคาตามระยะทาง (Messenger)" }),
1602
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "ตั้งช่วงราคาตามระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม. สำหรับบริการส่งด่วน 3 ชม." }),
1603
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: "/base-pricing", target: "_blank", rel: "noreferrer", children: [
1604
- "จัดการฐานราคา",
1605
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "ml-1 h-4 w-4" })
1606
- ] }) }) })
1607
- ] }),
1608
1550
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
1609
1551
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1610
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
1552
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "unit", children: "หน่วย *" }),
1611
1553
  /* @__PURE__ */ jsxRuntime.jsx(
1612
1554
  ui.Input,
1613
1555
  {
1614
- id: "maxWeight",
1615
- type: "number",
1616
- step: "0.1",
1617
- min: "0",
1618
- value: formData.max_weight_kg,
1619
- onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
1620
- placeholder: "เช่น 3",
1556
+ id: "unit",
1557
+ value: formData.unit,
1558
+ onChange: (e) => setFormData({ ...formData, unit: e.target.value }),
1559
+ placeholder: "เช่น ชิ้น, เมตร, กิโลกรัม",
1621
1560
  required: true
1622
1561
  }
1623
1562
  )
1624
1563
  ] }),
1625
1564
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1626
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
1565
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "costPerUnit", children: "ต้นทุนต่อหน่วย *" }),
1627
1566
  /* @__PURE__ */ jsxRuntime.jsx(
1628
1567
  ui.Input,
1629
1568
  {
1630
- id: "price",
1569
+ id: "costPerUnit",
1631
1570
  type: "number",
1632
1571
  step: "0.01",
1633
- min: "0",
1634
- value: formData.price,
1635
- onChange: (e) => setFormData({ ...formData, price: e.target.value }),
1636
- placeholder: "เช่น 80",
1572
+ value: formData.cost_per_unit,
1573
+ onChange: (e) => setFormData({ ...formData, cost_per_unit: e.target.value }),
1574
+ placeholder: "0.00",
1637
1575
  required: true
1638
1576
  }
1639
1577
  )
1640
1578
  ] })
1641
1579
  ] }),
1642
1580
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1643
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
1581
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "currency", children: "สกุลเงิน" }),
1644
1582
  /* @__PURE__ */ jsxRuntime.jsx(
1645
1583
  ui.Input,
1646
1584
  {
1647
- id: "priority",
1648
- type: "number",
1649
- value: formData.priority,
1650
- onChange: (e) => setFormData({ ...formData, priority: e.target.value }),
1651
- placeholder: "0"
1585
+ id: "currency",
1586
+ value: formData.currency,
1587
+ onChange: (e) => setFormData({ ...formData, currency: e.target.value }),
1588
+ placeholder: "THB"
1652
1589
  }
1653
- ),
1654
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ตัวเลขสูงกว่าจะถูกเสนอให้เลือกก่อน (ค่าเริ่มต้น 0)" })
1590
+ )
1655
1591
  ] }),
1656
1592
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1657
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Label, { children: [
1658
- usesHours ? "ETA (ชั่วโมง)" : "ETA (วัน)",
1659
- " *"
1660
- ] }),
1661
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 mt-2", children: usesHours ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1662
- /* @__PURE__ */ jsxRuntime.jsx(
1663
- ui.Input,
1664
- {
1665
- type: "number",
1666
- placeholder: "ต่ำสุด",
1667
- value: formData.eta_hours_min,
1668
- onChange: (e) => setFormData({ ...formData, eta_hours_min: e.target.value }),
1669
- required: true
1670
- }
1671
- ),
1672
- /* @__PURE__ */ jsxRuntime.jsx(
1673
- ui.Input,
1674
- {
1675
- type: "number",
1676
- placeholder: "สูงสุด",
1677
- value: formData.eta_hours_max,
1678
- onChange: (e) => setFormData({ ...formData, eta_hours_max: e.target.value }),
1679
- required: true
1680
- }
1681
- )
1682
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1683
- /* @__PURE__ */ jsxRuntime.jsx(
1684
- ui.Input,
1685
- {
1686
- type: "number",
1687
- placeholder: "ต่ำสุด",
1688
- value: formData.eta_days_min,
1689
- onChange: (e) => setFormData({ ...formData, eta_days_min: e.target.value }),
1690
- required: true
1691
- }
1692
- ),
1693
- /* @__PURE__ */ jsxRuntime.jsx(
1694
- ui.Input,
1695
- {
1696
- type: "number",
1697
- placeholder: "สูงสุด",
1698
- value: formData.eta_days_max,
1699
- onChange: (e) => setFormData({ ...formData, eta_days_max: e.target.value }),
1700
- required: true
1701
- }
1702
- )
1703
- ] }) })
1704
- ] }),
1705
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
1593
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "description", children: "คำอธิบาย" }),
1706
1594
  /* @__PURE__ */ jsxRuntime.jsx(
1707
- ui.Switch,
1595
+ ui.Textarea,
1596
+ {
1597
+ id: "description",
1598
+ value: formData.description,
1599
+ onChange: (e) => setFormData({ ...formData, description: e.target.value }),
1600
+ placeholder: "คำอธิบายเพิ่มเติมเกี่ยวกับวัสดุนี้...",
1601
+ rows: 3
1602
+ }
1603
+ )
1604
+ ] }),
1605
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
1606
+ /* @__PURE__ */ jsxRuntime.jsx(
1607
+ ui.Switch,
1708
1608
  {
1709
1609
  id: "active",
1710
1610
  checked: formData.active,
@@ -1714,168 +1614,202 @@ const ShippingRateModal = ({ rate, onClose }) => {
1714
1614
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
1715
1615
  ] }),
1716
1616
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
1717
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
1617
+ /* @__PURE__ */ jsxRuntime.jsx(
1618
+ ui.Button,
1619
+ {
1620
+ type: "button",
1621
+ variant: "secondary",
1622
+ onClick: onClose,
1623
+ disabled: isSaving,
1624
+ children: "ยกเลิก"
1625
+ }
1626
+ ),
1718
1627
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
1719
1628
  ] })
1720
1629
  ] }) })
1721
1630
  ] }) });
1722
1631
  };
1723
- const CARRIER_TYPES = [
1724
- { value: "ALL", label: "ทั้งหมด" },
1725
- { value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
1726
- { value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
1727
- { value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
1728
- ];
1729
- const SERVICE_CODES = [
1632
+ const CATEGORIES = [
1730
1633
  { value: "ALL", label: "ทั้งหมด" },
1731
- { value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม." },
1732
- { value: "SAME_DAY", label: "ส่งด่วนภายในวัน" },
1733
- { value: "STANDARD_3_5D", label: "EMS 3-5 วัน" },
1734
- { value: "EXPRESS_1_2D", label: "Express 1-2 วัน" }
1634
+ { value: "PACKAGING", label: "วัสดุหีบห่อ" },
1635
+ { value: "PROTECTION", label: "วัสดุป้องกัน" },
1636
+ { value: "FILLING", label: "วัสดุเติมช่องว่าง" },
1637
+ { value: "TAPE", label: "เทป/กาว" },
1638
+ { value: "LABEL", label: "ฉลาก/สติกเกอร์" },
1639
+ { value: "OTHER", label: "อื่นๆ" }
1735
1640
  ];
1736
- const ShippingRatesTable = () => {
1737
- const [rates, setRates] = react.useState([]);
1738
- const [filteredRates, setFilteredRates] = react.useState([]);
1739
- const [carrierFilter, setCarrierFilter] = react.useState("ALL");
1740
- const [serviceFilter, setServiceFilter] = react.useState("ALL");
1641
+ const MaterialCostsTable = () => {
1642
+ const [materialCosts, setMaterialCosts] = react.useState([]);
1643
+ const [filteredMaterialCosts, setFilteredMaterialCosts] = react.useState([]);
1644
+ const [searchTerm, setSearchTerm] = react.useState("");
1645
+ const [categoryFilter, setCategoryFilter] = react.useState("ALL");
1741
1646
  const [isModalOpen, setIsModalOpen] = react.useState(false);
1742
- const [editingRate, setEditingRate] = react.useState(null);
1647
+ const [editingMaterialCost, setEditingMaterialCost] = react.useState(null);
1743
1648
  const [isLoading, setIsLoading] = react.useState(false);
1744
- const [deleteRateId, setDeleteRateId] = react.useState(null);
1649
+ const [deleteMaterialCostId, setDeleteMaterialCostId] = react.useState(null);
1650
+ const [deleteMaterialCostName, setDeleteMaterialCostName] = react.useState("");
1745
1651
  react.useEffect(() => {
1746
- fetchRates();
1652
+ fetchMaterialCosts();
1747
1653
  }, []);
1748
1654
  react.useEffect(() => {
1749
- let filtered = rates;
1750
- if (carrierFilter !== "ALL") {
1751
- filtered = filtered.filter((rate) => rate.carrier_type === carrierFilter);
1655
+ let filtered = materialCosts;
1656
+ if (categoryFilter !== "ALL") {
1657
+ filtered = filtered.filter((mc) => mc.category === categoryFilter);
1752
1658
  }
1753
- if (serviceFilter !== "ALL") {
1754
- filtered = filtered.filter((rate) => rate.service_code === serviceFilter);
1659
+ if (searchTerm) {
1660
+ filtered = filtered.filter(
1661
+ (mc) => mc.name.toLowerCase().includes(searchTerm.toLowerCase())
1662
+ );
1755
1663
  }
1756
- setFilteredRates(filtered);
1757
- }, [carrierFilter, serviceFilter, rates]);
1758
- const fetchRates = async () => {
1664
+ setFilteredMaterialCosts(filtered);
1665
+ }, [searchTerm, categoryFilter, materialCosts]);
1666
+ const fetchMaterialCosts = async () => {
1759
1667
  setIsLoading(true);
1760
1668
  try {
1761
- const response = await fetch("/admin/shipping-rates", {
1669
+ const response = await fetch("/admin/material-costs", {
1762
1670
  credentials: "include"
1763
1671
  });
1764
1672
  const data = await response.json();
1765
- setRates(data.rates || []);
1673
+ setMaterialCosts(data.material_costs || []);
1766
1674
  } catch (error) {
1767
1675
  ui.toast.error("ข้อผิดพลาด", {
1768
- description: "ไม่สามารถโหลดข้อมูลอัตราค่าขนส่งได้"
1676
+ description: "ไม่สามารถโหลดข้อมูลต้นทุนวัสดุได้"
1769
1677
  });
1770
1678
  } finally {
1771
1679
  setIsLoading(false);
1772
1680
  }
1773
1681
  };
1774
- const handleDelete = async () => {
1775
- if (!deleteRateId) return;
1682
+ const handleToggleActive = async (materialCost) => {
1776
1683
  try {
1777
- const response = await fetch(`/admin/shipping-rates/${deleteRateId}`, {
1778
- method: "DELETE",
1779
- credentials: "include"
1684
+ const response = await fetch(`/admin/material-costs/${materialCost.id}`, {
1685
+ method: "PUT",
1686
+ headers: { "Content-Type": "application/json" },
1687
+ credentials: "include",
1688
+ body: JSON.stringify({ ...materialCost, active: !materialCost.active })
1780
1689
  });
1781
1690
  if (response.ok) {
1782
1691
  ui.toast.success("สำเร็จ", {
1783
- description: "ลบอัตราค่าขนส่งแล้ว"
1692
+ description: `${materialCost.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}วัสดุ ${materialCost.name} แล้ว`
1784
1693
  });
1785
- fetchRates();
1694
+ fetchMaterialCosts();
1695
+ } else {
1696
+ throw new Error("Failed to update");
1697
+ }
1698
+ } catch (error) {
1699
+ ui.toast.error("ข้อผิดพลาด", {
1700
+ description: "ไม่สามารถอัพเดทสถานะได้"
1701
+ });
1702
+ }
1703
+ };
1704
+ const handleDelete = async () => {
1705
+ if (!deleteMaterialCostId) return;
1706
+ try {
1707
+ const response = await fetch(
1708
+ `/admin/material-costs/${deleteMaterialCostId}`,
1709
+ {
1710
+ method: "DELETE",
1711
+ credentials: "include"
1712
+ }
1713
+ );
1714
+ if (response.ok) {
1715
+ ui.toast.success("สำเร็จ", {
1716
+ description: `ลบวัสดุ ${deleteMaterialCostName} แล้ว`
1717
+ });
1718
+ fetchMaterialCosts();
1786
1719
  } else {
1787
1720
  throw new Error("Failed to delete");
1788
1721
  }
1789
1722
  } catch (error) {
1790
1723
  ui.toast.error("ข้อผิดพลาด", {
1791
- description: "ไม่สามารถลบอัตราค่าขนส่งได้"
1724
+ description: "ไม่สามารถลบวัสดุได้"
1792
1725
  });
1793
1726
  } finally {
1794
- setDeleteRateId(null);
1727
+ setDeleteMaterialCostId(null);
1728
+ setDeleteMaterialCostName("");
1795
1729
  }
1796
1730
  };
1797
- const handleEdit = (rate) => {
1798
- setEditingRate(rate);
1731
+ const handleEdit = (materialCost) => {
1732
+ setEditingMaterialCost(materialCost);
1799
1733
  setIsModalOpen(true);
1800
1734
  };
1801
1735
  const handleCreateNew = () => {
1802
- setEditingRate(null);
1736
+ setEditingMaterialCost(null);
1803
1737
  setIsModalOpen(true);
1804
1738
  };
1805
1739
  const handleModalClose = () => {
1806
1740
  setIsModalOpen(false);
1807
- setEditingRate(null);
1808
- fetchRates();
1741
+ setEditingMaterialCost(null);
1742
+ fetchMaterialCosts();
1809
1743
  };
1810
- const getCarrierLabel = (type) => {
1811
- var _a;
1812
- return ((_a = CARRIER_TYPES.find((c) => c.value === type)) == null ? void 0 : _a.label) || type;
1744
+ const openDeletePrompt = (id, name) => {
1745
+ setDeleteMaterialCostId(id);
1746
+ setDeleteMaterialCostName(name);
1813
1747
  };
1814
- const getServiceLabel = (code) => {
1748
+ const getCategoryLabel = (category) => {
1815
1749
  var _a;
1816
- return ((_a = SERVICE_CODES.find((s) => s.value === code)) == null ? void 0 : _a.label) || code;
1817
- };
1818
- const formatETA = (rate) => {
1819
- if (rate.eta_hours_min !== null && rate.eta_hours_min !== void 0 && rate.eta_hours_max !== null && rate.eta_hours_max !== void 0) {
1820
- return `${rate.eta_hours_min}-${rate.eta_hours_max} ชม.`;
1821
- }
1822
- if (rate.eta_days_min !== null && rate.eta_days_min !== void 0 && rate.eta_days_max !== null && rate.eta_days_max !== void 0) {
1823
- return `${rate.eta_days_min}-${rate.eta_days_max} วัน`;
1824
- }
1825
- return "-";
1750
+ if (!category) return "-";
1751
+ return ((_a = CATEGORIES.find((c) => c.value === category)) == null ? void 0 : _a.label) || category;
1826
1752
  };
1827
1753
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1828
1754
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
1829
1755
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
1830
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 items-end", children: [
1831
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1832
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "ประเภทขนส่ง" }),
1833
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: carrierFilter, onValueChange: setCarrierFilter, children: [
1834
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
1835
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES.map((type) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: type.value, children: type.label }, type.value)) })
1836
- ] })
1837
- ] }),
1838
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1839
- /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "บริการจัดส่ง" }),
1840
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: serviceFilter, onValueChange: setServiceFilter, children: [
1841
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
1842
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
1843
- ] })
1756
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 flex-1", children: [
1757
+ /* @__PURE__ */ jsxRuntime.jsx(
1758
+ ui.Input,
1759
+ {
1760
+ type: "search",
1761
+ placeholder: "ค้นหาชื่อวัสดุ...",
1762
+ value: searchTerm,
1763
+ onChange: (e) => setSearchTerm(e.target.value),
1764
+ className: "max-w-md"
1765
+ }
1766
+ ),
1767
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: categoryFilter, onValueChange: setCategoryFilter, children: [
1768
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "หมวดหมู่" }) }),
1769
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
1844
1770
  ] })
1845
1771
  ] }),
1846
1772
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
1847
1773
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
1848
- "สร้างอัตราใหม่"
1774
+ "สร้างรายการใหม่"
1849
1775
  ] })
1850
1776
  ] }),
1851
1777
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
1852
1778
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1853
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ประเภทขนส่ง" }),
1854
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "บริการ" }),
1855
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "น้ำหนัก ≤ (kg)" }),
1856
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
1857
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ETA" }),
1779
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ชื่อ" }),
1780
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หมวดหมู่" }),
1781
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หน่วย" }),
1782
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ต้นทุนต่อหน่วย" }),
1783
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "คำอธิบาย" }),
1858
1784
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
1859
1785
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
1860
1786
  ] }) }),
1861
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredRates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลอัตราค่าขนส่ง" }) }) : filteredRates.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1862
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getCarrierLabel(rate.carrier_type) }),
1863
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getServiceLabel(rate.service_code) }),
1787
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredMaterialCosts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลต้นทุนวัสดุ" }) }) : filteredMaterialCosts.map((materialCost) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1788
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.name }),
1789
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: getCategoryLabel(materialCost.category) }) }),
1790
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.unit }),
1864
1791
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
1865
- "≤ ",
1866
- rate.max_weight_kg,
1867
- " kg"
1792
+ materialCost.cost_per_unit.toFixed(2),
1793
+ " ",
1794
+ materialCost.currency
1868
1795
  ] }),
1869
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: rate.price.toFixed(2) }),
1870
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: formatETA(rate) }) }),
1871
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
1796
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-xs truncate", children: materialCost.description || "-" }),
1797
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
1798
+ ui.Badge,
1799
+ {
1800
+ color: materialCost.active ? "green" : "grey",
1801
+ className: "cursor-pointer",
1802
+ onClick: () => handleToggleActive(materialCost),
1803
+ children: materialCost.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
1804
+ }
1805
+ ) }),
1872
1806
  /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
1873
1807
  /* @__PURE__ */ jsxRuntime.jsx(
1874
1808
  ui.Button,
1875
1809
  {
1876
1810
  variant: "transparent",
1877
1811
  size: "small",
1878
- onClick: () => handleEdit(rate),
1812
+ onClick: () => handleEdit(materialCost),
1879
1813
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
1880
1814
  }
1881
1815
  ),
@@ -1884,25 +1818,38 @@ const ShippingRatesTable = () => {
1884
1818
  {
1885
1819
  variant: "transparent",
1886
1820
  size: "small",
1887
- onClick: () => setDeleteRateId(rate.id),
1821
+ onClick: () => openDeletePrompt(materialCost.id, materialCost.name),
1888
1822
  children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
1889
1823
  }
1890
1824
  )
1891
1825
  ] }) })
1892
- ] }, rate.id)) })
1826
+ ] }, materialCost.id)) })
1893
1827
  ] })
1894
1828
  ] }),
1895
- isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ShippingRateModal, { rate: editingRate, onClose: handleModalClose }),
1829
+ isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
1830
+ MaterialCostModal,
1831
+ {
1832
+ materialCost: editingMaterialCost,
1833
+ onClose: handleModalClose
1834
+ }
1835
+ ),
1896
1836
  /* @__PURE__ */ jsxRuntime.jsx(
1897
1837
  ui.Prompt,
1898
1838
  {
1899
1839
  variant: "confirmation",
1900
- open: !!deleteRateId,
1901
- onOpenChange: () => setDeleteRateId(null),
1840
+ open: !!deleteMaterialCostId,
1841
+ onOpenChange: () => {
1842
+ setDeleteMaterialCostId(null);
1843
+ setDeleteMaterialCostName("");
1844
+ },
1902
1845
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
1903
1846
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
1904
- /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบอัตราค่าขนส่ง" }),
1905
- /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: "คุณต้องการลบอัตราค่าขนส่งนี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
1847
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบรายการต้นทุนวัสดุ" }),
1848
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Description, { children: [
1849
+ 'คุณต้องการลบวัสดุ "',
1850
+ deleteMaterialCostName,
1851
+ '" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
1852
+ ] })
1906
1853
  ] }),
1907
1854
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [
1908
1855
  /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: "ยกเลิก" }),
@@ -1913,26 +1860,59 @@ const ShippingRatesTable = () => {
1913
1860
  )
1914
1861
  ] });
1915
1862
  };
1916
- const CompanyTruckBaseRateModal = ({
1917
- rate,
1918
- onClose
1919
- }) => {
1920
- const [formData, setFormData] = react.useState({
1921
- min_distance_km: "0",
1922
- max_distance_km: "",
1863
+ const MaterialCostsPage = () => {
1864
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
1865
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "ต้นทุนวัสดุ" }) }),
1866
+ /* @__PURE__ */ jsxRuntime.jsx(MaterialCostsTable, {})
1867
+ ] }) });
1868
+ };
1869
+ const config$1 = adminSdk.defineRouteConfig({
1870
+ icon: icons.CurrencyDollarSolid,
1871
+ label: "ต้นทุนวัสดุ"
1872
+ });
1873
+ const CARRIER_TYPES$1 = [
1874
+ { value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
1875
+ { value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
1876
+ { value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
1877
+ ];
1878
+ const SERVICE_CODES$1 = [
1879
+ { value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม.", usesHours: true },
1880
+ { value: "SAME_DAY", label: "ส่งด่วนภายในวัน", usesHours: true },
1881
+ { value: "STANDARD_3_5D", label: "EMS 3-5 วัน", usesHours: false },
1882
+ { value: "EXPRESS_1_2D", label: "Express 1-2 วัน", usesHours: false }
1883
+ ];
1884
+ const ShippingRateModal = ({ rate, onClose }) => {
1885
+ const [formData, setFormData] = react.useState({
1886
+ carrier_type: "COMPANY_FLEET",
1887
+ service_code: "MESSENGER_3H",
1888
+ max_weight_kg: "",
1923
1889
  price: "",
1890
+ currency: "THB",
1924
1891
  priority: "0",
1892
+ eta_hours_min: "",
1893
+ eta_hours_max: "",
1894
+ eta_days_min: "",
1895
+ eta_days_max: "",
1925
1896
  active: true
1926
1897
  });
1927
1898
  const [isSaving, setIsSaving] = react.useState(false);
1899
+ const selectedService = SERVICE_CODES$1.find((s) => s.value === formData.service_code);
1900
+ const usesHours = (selectedService == null ? void 0 : selectedService.usesHours) ?? false;
1901
+ const isMessenger = formData.carrier_type === "COMPANY_FLEET" && formData.service_code === "MESSENGER_3H";
1928
1902
  react.useEffect(() => {
1929
- var _a, _b;
1903
+ var _a, _b, _c, _d;
1930
1904
  if (rate) {
1931
1905
  setFormData({
1932
- min_distance_km: ((_a = rate.min_distance_km) == null ? void 0 : _a.toString()) ?? "0",
1933
- max_distance_km: ((_b = rate.max_distance_km) == null ? void 0 : _b.toString()) || "",
1906
+ carrier_type: rate.carrier_type,
1907
+ service_code: rate.service_code,
1908
+ max_weight_kg: rate.max_weight_kg.toString(),
1934
1909
  price: rate.price.toString(),
1910
+ currency: rate.currency,
1935
1911
  priority: (rate.priority ?? 0).toString(),
1912
+ eta_hours_min: ((_a = rate.eta_hours_min) == null ? void 0 : _a.toString()) || "",
1913
+ eta_hours_max: ((_b = rate.eta_hours_max) == null ? void 0 : _b.toString()) || "",
1914
+ eta_days_min: ((_c = rate.eta_days_min) == null ? void 0 : _c.toString()) || "",
1915
+ eta_days_max: ((_d = rate.eta_days_max) == null ? void 0 : _d.toString()) || "",
1936
1916
  active: rate.active
1937
1917
  });
1938
1918
  }
@@ -1940,16 +1920,11 @@ const CompanyTruckBaseRateModal = ({
1940
1920
  const handleSubmit = async (e) => {
1941
1921
  e.preventDefault();
1942
1922
  const errors = [];
1943
- const minDistance = parseFloat(formData.min_distance_km || "0");
1944
- const hasMaxDistance = formData.max_distance_km !== "";
1945
- const maxDistance = hasMaxDistance ? parseFloat(formData.max_distance_km) : void 0;
1923
+ const maxWeight = parseFloat(formData.max_weight_kg);
1946
1924
  const price = parseFloat(formData.price);
1947
- const priority = parseInt(formData.priority || "0", 10);
1948
- if (isNaN(minDistance) || minDistance < 0) {
1949
- errors.push("ระยะทางเริ่มต้นต้องไม่ติดลบ");
1950
- }
1951
- if (hasMaxDistance && (maxDistance === void 0 || isNaN(maxDistance) || (maxDistance ?? 0) < minDistance)) {
1952
- errors.push("ระยะทางสูงสุดต้องมากกว่าหรือเท่ากับระยะทางเริ่มต้น");
1925
+ const priority = parseInt(formData.priority);
1926
+ if (isNaN(maxWeight) || maxWeight <= 0) {
1927
+ errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
1953
1928
  }
1954
1929
  if (isNaN(price) || price < 0) {
1955
1930
  errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
@@ -1957,6 +1932,27 @@ const CompanyTruckBaseRateModal = ({
1957
1932
  if (isNaN(priority)) {
1958
1933
  errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
1959
1934
  }
1935
+ let etaHoursMin;
1936
+ let etaHoursMax;
1937
+ let etaDaysMin;
1938
+ let etaDaysMax;
1939
+ if (usesHours) {
1940
+ etaHoursMin = formData.eta_hours_min ? parseFloat(formData.eta_hours_min) : void 0;
1941
+ etaHoursMax = formData.eta_hours_max ? parseFloat(formData.eta_hours_max) : void 0;
1942
+ if (etaHoursMin === void 0 || etaHoursMax === void 0) {
1943
+ errors.push("กรุณากรอก ETA เป็นชั่วโมงให้ครบ");
1944
+ } else if (etaHoursMin > etaHoursMax) {
1945
+ errors.push("ETA ชั่วโมงต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
1946
+ }
1947
+ } else {
1948
+ etaDaysMin = formData.eta_days_min ? parseFloat(formData.eta_days_min) : void 0;
1949
+ etaDaysMax = formData.eta_days_max ? parseFloat(formData.eta_days_max) : void 0;
1950
+ if (etaDaysMin === void 0 || etaDaysMax === void 0) {
1951
+ errors.push("กรุณากรอก ETA เป็นวันให้ครบ");
1952
+ } else if (etaDaysMin > etaDaysMax) {
1953
+ errors.push("ETA วันต่ำสุดต้องน้อยกว่าหรือเท่ากับสูงสุด");
1954
+ }
1955
+ }
1960
1956
  if (errors.length > 0) {
1961
1957
  ui.toast.error("ข้อมูลไม่ถูกต้อง", {
1962
1958
  description: errors.join(", ")
@@ -1966,17 +1962,22 @@ const CompanyTruckBaseRateModal = ({
1966
1962
  setIsSaving(true);
1967
1963
  try {
1968
1964
  const payload = {
1969
- carrier_type: "COMPANY_TRUCK",
1970
- carrier: "COMPANY_TRUCK",
1971
- service_code: "SAME_DAY",
1972
- min_distance_km: minDistance,
1973
- max_distance_km: maxDistance === void 0 || isNaN(maxDistance) ? null : maxDistance,
1965
+ carrier_type: formData.carrier_type,
1966
+ service_code: formData.service_code,
1967
+ max_weight_kg: maxWeight,
1974
1968
  price,
1975
- currency: "THB",
1969
+ currency: formData.currency,
1976
1970
  priority,
1977
1971
  active: formData.active
1978
1972
  };
1979
- const url = rate ? `/admin/base-shipping-prices/${rate.id}` : "/admin/base-shipping-prices";
1973
+ if (usesHours) {
1974
+ payload.eta_hours_min = etaHoursMin;
1975
+ payload.eta_hours_max = etaHoursMax;
1976
+ } else {
1977
+ payload.eta_days_min = etaDaysMin;
1978
+ payload.eta_days_max = etaDaysMax;
1979
+ }
1980
+ const url = rate ? `/admin/shipping-rates/${rate.id}` : "/admin/shipping-rates";
1980
1981
  const method = rate ? "PUT" : "POST";
1981
1982
  const response = await fetch(url, {
1982
1983
  method,
@@ -1984,14 +1985,15 @@ const CompanyTruckBaseRateModal = ({
1984
1985
  credentials: "include",
1985
1986
  body: JSON.stringify(payload)
1986
1987
  });
1987
- if (!response.ok) {
1988
- const error = await response.json().catch(() => ({}));
1989
- throw new Error(error.message || "ไม่สามารถบันทึกข้อมูลได้");
1988
+ if (response.ok) {
1989
+ ui.toast.success("สำเร็จ", {
1990
+ description: rate ? "แก้ไขอัตราค่าขนส่งแล้ว" : "สร้างอัตราค่าขนส่งใหม่แล้ว"
1991
+ });
1992
+ onClose();
1993
+ } else {
1994
+ const error = await response.json();
1995
+ throw new Error(error.message || "Failed to save");
1990
1996
  }
1991
- ui.toast.success("สำเร็จ", {
1992
- description: rate ? "แก้ไขฐานราคาตามระยะทางแล้ว" : "สร้างฐานราคาตามระยะทางใหม่แล้ว"
1993
- });
1994
- onClose();
1995
1997
  } catch (error) {
1996
1998
  ui.toast.error("ข้อผิดพลาด", {
1997
1999
  description: error instanceof Error ? error.message : "ไม่สามารถบันทึกข้อมูลได้"
@@ -2001,56 +2003,85 @@ const CompanyTruckBaseRateModal = ({
2001
2003
  }
2002
2004
  };
2003
2005
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
2004
- /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: rate ? "แก้ไขฐานราคาตามระยะทาง (รถบริษัท)" : "สร้างฐานราคาตามระยะทาง (รถบริษัท)" }) }),
2006
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: rate ? "แก้ไขอัตราค่าขนส่ง" : "สร้างอัตราค่าขนส่งใหม่" }) }),
2005
2007
  /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
2008
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2009
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "carrier", children: "ประเภทขนส่ง *" }),
2010
+ /* @__PURE__ */ jsxRuntime.jsxs(
2011
+ ui.Select,
2012
+ {
2013
+ value: formData.carrier_type,
2014
+ onValueChange: (value) => setFormData({ ...formData, carrier_type: value }),
2015
+ children: [
2016
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกประเภทขนส่ง" }) }),
2017
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES$1.map((carrier) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: carrier.value, children: carrier.label }, carrier.value)) })
2018
+ ]
2019
+ }
2020
+ )
2021
+ ] }),
2022
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2023
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "service", children: "บริการจัดส่ง *" }),
2024
+ /* @__PURE__ */ jsxRuntime.jsxs(
2025
+ ui.Select,
2026
+ {
2027
+ value: formData.service_code,
2028
+ onValueChange: (value) => setFormData({
2029
+ ...formData,
2030
+ service_code: value,
2031
+ eta_hours_min: "",
2032
+ eta_hours_max: "",
2033
+ eta_days_min: "",
2034
+ eta_days_max: ""
2035
+ }),
2036
+ children: [
2037
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกบริการ" }) }),
2038
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES$1.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
2039
+ ]
2040
+ }
2041
+ )
2042
+ ] }),
2043
+ isMessenger && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base bg-ui-bg-subtle p-3 text-sm space-y-1", children: [
2044
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-semibold text-ui-fg-base", children: "ฐานราคาตามระยะทาง (Messenger)" }),
2045
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-subtle", children: "ตั้งช่วงราคาตามระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม. สำหรับบริการส่งด่วน 3 ชม." }),
2046
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { asChild: true, size: "small", variant: "secondary", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: "/base-pricing", target: "_blank", rel: "noreferrer", children: [
2047
+ "จัดการฐานราคา",
2048
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ExternalLink, { className: "ml-1 h-4 w-4" })
2049
+ ] }) }) })
2050
+ ] }),
2006
2051
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
2007
2052
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2008
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "min_distance_km", children: "ระยะทางเริ่มต้น (กม.) *" }),
2053
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
2009
2054
  /* @__PURE__ */ jsxRuntime.jsx(
2010
2055
  ui.Input,
2011
2056
  {
2012
- id: "min_distance_km",
2057
+ id: "maxWeight",
2013
2058
  type: "number",
2014
- min: "0",
2015
2059
  step: "0.1",
2016
- value: formData.min_distance_km,
2017
- onChange: (e) => setFormData({ ...formData, min_distance_km: e.target.value }),
2060
+ min: "0",
2061
+ value: formData.max_weight_kg,
2062
+ onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
2063
+ placeholder: "เช่น 3",
2018
2064
  required: true
2019
2065
  }
2020
2066
  )
2021
2067
  ] }),
2022
2068
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2023
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "max_distance_km", children: "ระยะทางสูงสุด (กม.)" }),
2069
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
2024
2070
  /* @__PURE__ */ jsxRuntime.jsx(
2025
2071
  ui.Input,
2026
2072
  {
2027
- id: "max_distance_km",
2073
+ id: "price",
2028
2074
  type: "number",
2075
+ step: "0.01",
2029
2076
  min: "0",
2030
- step: "0.1",
2031
- placeholder: "ปล่อยว่างหากไม่มีที่สิ้นสุด",
2032
- value: formData.max_distance_km,
2033
- onChange: (e) => setFormData({ ...formData, max_distance_km: e.target.value })
2077
+ value: formData.price,
2078
+ onChange: (e) => setFormData({ ...formData, price: e.target.value }),
2079
+ placeholder: "เช่น 80",
2080
+ required: true
2034
2081
  }
2035
- ),
2036
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "เว้นว่างเพื่อกำหนดช่วงราคาแบบ 30+ กม." })
2082
+ )
2037
2083
  ] })
2038
2084
  ] }),
2039
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2040
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
2041
- /* @__PURE__ */ jsxRuntime.jsx(
2042
- ui.Input,
2043
- {
2044
- id: "price",
2045
- type: "number",
2046
- min: "0",
2047
- step: "0.01",
2048
- value: formData.price,
2049
- onChange: (e) => setFormData({ ...formData, price: e.target.value }),
2050
- required: true
2051
- }
2052
- )
2053
- ] }),
2054
2085
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2055
2086
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
2056
2087
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2063,7 +2094,56 @@ const CompanyTruckBaseRateModal = ({
2063
2094
  placeholder: "0"
2064
2095
  }
2065
2096
  ),
2066
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ใช้สำหรับจัดลำดับเมื่อมีช่วงราคาทับกัน (ค่าเริ่มต้น 0)" })
2097
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ตัวเลขสูงกว่าจะถูกเสนอให้เลือกก่อน (ค่าเริ่มต้น 0)" })
2098
+ ] }),
2099
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2100
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Label, { children: [
2101
+ usesHours ? "ETA (ชั่วโมง)" : "ETA (วัน)",
2102
+ " *"
2103
+ ] }),
2104
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 mt-2", children: usesHours ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2105
+ /* @__PURE__ */ jsxRuntime.jsx(
2106
+ ui.Input,
2107
+ {
2108
+ type: "number",
2109
+ placeholder: "ต่ำสุด",
2110
+ value: formData.eta_hours_min,
2111
+ onChange: (e) => setFormData({ ...formData, eta_hours_min: e.target.value }),
2112
+ required: true
2113
+ }
2114
+ ),
2115
+ /* @__PURE__ */ jsxRuntime.jsx(
2116
+ ui.Input,
2117
+ {
2118
+ type: "number",
2119
+ placeholder: "สูงสุด",
2120
+ value: formData.eta_hours_max,
2121
+ onChange: (e) => setFormData({ ...formData, eta_hours_max: e.target.value }),
2122
+ required: true
2123
+ }
2124
+ )
2125
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2126
+ /* @__PURE__ */ jsxRuntime.jsx(
2127
+ ui.Input,
2128
+ {
2129
+ type: "number",
2130
+ placeholder: "ต่ำสุด",
2131
+ value: formData.eta_days_min,
2132
+ onChange: (e) => setFormData({ ...formData, eta_days_min: e.target.value }),
2133
+ required: true
2134
+ }
2135
+ ),
2136
+ /* @__PURE__ */ jsxRuntime.jsx(
2137
+ ui.Input,
2138
+ {
2139
+ type: "number",
2140
+ placeholder: "สูงสุด",
2141
+ value: formData.eta_days_max,
2142
+ onChange: (e) => setFormData({ ...formData, eta_days_max: e.target.value }),
2143
+ required: true
2144
+ }
2145
+ )
2146
+ ] }) })
2067
2147
  ] }),
2068
2148
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
2069
2149
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2077,163 +2157,195 @@ const CompanyTruckBaseRateModal = ({
2077
2157
  /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "active", children: "เปิดใช้งาน" })
2078
2158
  ] }),
2079
2159
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
2080
- /* @__PURE__ */ jsxRuntime.jsx(
2081
- ui.Button,
2082
- {
2083
- type: "button",
2084
- variant: "secondary",
2085
- onClick: onClose,
2086
- disabled: isSaving,
2087
- children: "ยกเลิก"
2088
- }
2089
- ),
2160
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
2090
2161
  /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
2091
2162
  ] })
2092
2163
  ] }) })
2093
2164
  ] }) });
2094
2165
  };
2095
- const CompanyTruckBasePricingTable = () => {
2166
+ const CARRIER_TYPES = [
2167
+ { value: "ALL", label: "ทั้งหมด" },
2168
+ { value: "COMPANY_FLEET", label: "บริษัทรถส่งของ (Messenger)" },
2169
+ { value: "COMPANY_TRUCK", label: "รถบริษัท (Same Day)" },
2170
+ { value: "PRIVATE_CARRIER", label: "ขนส่งเอกชน (EMS/Express)" }
2171
+ ];
2172
+ const SERVICE_CODES = [
2173
+ { value: "ALL", label: "ทั้งหมด" },
2174
+ { value: "MESSENGER_3H", label: "ส่งด่วน 3 ชม." },
2175
+ { value: "SAME_DAY", label: "ส่งด่วนภายในวัน" },
2176
+ { value: "STANDARD_3_5D", label: "EMS 3-5 วัน" },
2177
+ { value: "EXPRESS_1_2D", label: "Express 1-2 วัน" }
2178
+ ];
2179
+ const ShippingRatesTable = () => {
2096
2180
  const [rates, setRates] = react.useState([]);
2097
- const [isLoading, setIsLoading] = react.useState(false);
2181
+ const [filteredRates, setFilteredRates] = react.useState([]);
2182
+ const [carrierFilter, setCarrierFilter] = react.useState("ALL");
2183
+ const [serviceFilter, setServiceFilter] = react.useState("ALL");
2098
2184
  const [isModalOpen, setIsModalOpen] = react.useState(false);
2099
2185
  const [editingRate, setEditingRate] = react.useState(null);
2100
- const [deleteId, setDeleteId] = react.useState(null);
2186
+ const [isLoading, setIsLoading] = react.useState(false);
2187
+ const [deleteRateId, setDeleteRateId] = react.useState(null);
2101
2188
  react.useEffect(() => {
2102
2189
  fetchRates();
2103
2190
  }, []);
2104
- const orderedRates = react.useMemo(() => {
2105
- return [...rates].sort((a, b) => {
2106
- if (a.min_distance_km !== b.min_distance_km) {
2107
- return a.min_distance_km - b.min_distance_km;
2108
- }
2109
- const aMax = a.max_distance_km ?? Number.POSITIVE_INFINITY;
2110
- const bMax = b.max_distance_km ?? Number.POSITIVE_INFINITY;
2111
- return aMax - bMax;
2112
- });
2113
- }, [rates]);
2191
+ react.useEffect(() => {
2192
+ let filtered = rates;
2193
+ if (carrierFilter !== "ALL") {
2194
+ filtered = filtered.filter((rate) => rate.carrier_type === carrierFilter);
2195
+ }
2196
+ if (serviceFilter !== "ALL") {
2197
+ filtered = filtered.filter((rate) => rate.service_code === serviceFilter);
2198
+ }
2199
+ setFilteredRates(filtered);
2200
+ }, [carrierFilter, serviceFilter, rates]);
2114
2201
  const fetchRates = async () => {
2115
2202
  setIsLoading(true);
2116
2203
  try {
2117
- const response = await fetch(
2118
- "/admin/base-shipping-prices?carrier_type=COMPANY_TRUCK&service_code=SAME_DAY",
2119
- {
2120
- credentials: "include"
2121
- }
2122
- );
2123
- if (!response.ok) {
2124
- throw new Error("failed_to_load_base_rates");
2125
- }
2204
+ const response = await fetch("/admin/shipping-rates", {
2205
+ credentials: "include"
2206
+ });
2126
2207
  const data = await response.json();
2127
- setRates(data.base_rates || []);
2208
+ setRates(data.rates || []);
2128
2209
  } catch (error) {
2129
2210
  ui.toast.error("ข้อผิดพลาด", {
2130
- description: "ไม่สามารถโหลดฐานราคาตามระยะทางได้"
2211
+ description: "ไม่สามารถโหลดข้อมูลอัตราค่าขนส่งได้"
2131
2212
  });
2132
2213
  } finally {
2133
2214
  setIsLoading(false);
2134
2215
  }
2135
2216
  };
2136
2217
  const handleDelete = async () => {
2137
- if (!deleteId) return;
2218
+ if (!deleteRateId) return;
2138
2219
  try {
2139
- const response = await fetch(
2140
- `/admin/base-shipping-prices/${deleteId}`,
2141
- {
2142
- method: "DELETE",
2143
- credentials: "include"
2144
- }
2145
- );
2146
- if (!response.ok) {
2147
- throw new Error("failed_to_delete");
2148
- }
2149
- ui.toast.success("สำเร็จ", {
2150
- description: "ลบฐานราคาสำเร็จ"
2220
+ const response = await fetch(`/admin/shipping-rates/${deleteRateId}`, {
2221
+ method: "DELETE",
2222
+ credentials: "include"
2151
2223
  });
2152
- fetchRates();
2224
+ if (response.ok) {
2225
+ ui.toast.success("สำเร็จ", {
2226
+ description: "ลบอัตราค่าขนส่งแล้ว"
2227
+ });
2228
+ fetchRates();
2229
+ } else {
2230
+ throw new Error("Failed to delete");
2231
+ }
2153
2232
  } catch (error) {
2154
2233
  ui.toast.error("ข้อผิดพลาด", {
2155
- description: "ไม่สามารถลบฐานราคาได้"
2234
+ description: "ไม่สามารถลบอัตราค่าขนส่งได้"
2156
2235
  });
2157
2236
  } finally {
2158
- setDeleteId(null);
2237
+ setDeleteRateId(null);
2159
2238
  }
2160
2239
  };
2240
+ const handleEdit = (rate) => {
2241
+ setEditingRate(rate);
2242
+ setIsModalOpen(true);
2243
+ };
2244
+ const handleCreateNew = () => {
2245
+ setEditingRate(null);
2246
+ setIsModalOpen(true);
2247
+ };
2161
2248
  const handleModalClose = () => {
2162
2249
  setIsModalOpen(false);
2163
2250
  setEditingRate(null);
2164
2251
  fetchRates();
2165
2252
  };
2166
- const formatDistanceRange = (rate) => {
2167
- const min = rate.min_distance_km ?? 0;
2168
- const max = rate.max_distance_km;
2169
- if (max === void 0 || max === null) {
2170
- return `${min}+ กม.`;
2253
+ const getCarrierLabel = (type) => {
2254
+ var _a;
2255
+ return ((_a = CARRIER_TYPES.find((c) => c.value === type)) == null ? void 0 : _a.label) || type;
2256
+ };
2257
+ const getServiceLabel = (code) => {
2258
+ var _a;
2259
+ return ((_a = SERVICE_CODES.find((s) => s.value === code)) == null ? void 0 : _a.label) || code;
2260
+ };
2261
+ const formatETA = (rate) => {
2262
+ if (rate.eta_hours_min !== null && rate.eta_hours_min !== void 0 && rate.eta_hours_max !== null && rate.eta_hours_max !== void 0) {
2263
+ return `${rate.eta_hours_min}-${rate.eta_hours_max} ชม.`;
2171
2264
  }
2172
- return `${min}-${max} กม.`;
2265
+ if (rate.eta_days_min !== null && rate.eta_days_min !== void 0 && rate.eta_days_max !== null && rate.eta_days_max !== void 0) {
2266
+ return `${rate.eta_days_min}-${rate.eta_days_max} วัน`;
2267
+ }
2268
+ return "-";
2173
2269
  };
2174
2270
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2175
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
2176
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2177
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: "ฐานราคาตามระยะทาง (รถบริษัท - Same Day)" }),
2178
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-ui-fg-subtle text-sm", children: "กำหนดราคาเริ่มต้นตามระยะทาง เช่น 0-10, 10-30, 30-50, 50+ กม." })
2271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
2272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
2273
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 items-end", children: [
2274
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
2275
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "ประเภทขนส่ง" }),
2276
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: carrierFilter, onValueChange: setCarrierFilter, children: [
2277
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
2278
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CARRIER_TYPES.map((type) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: type.value, children: type.label }, type.value)) })
2279
+ ] })
2280
+ ] }),
2281
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
2282
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "text-sm font-medium text-ui-fg-subtle", children: "บริการจัดส่ง" }),
2283
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: serviceFilter, onValueChange: setServiceFilter, children: [
2284
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "ทั้งหมด" }) }),
2285
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: SERVICE_CODES.map((service) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: service.value, children: service.label }, service.value)) })
2286
+ ] })
2287
+ ] })
2288
+ ] }),
2289
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
2290
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
2291
+ "สร้างอัตราใหม่"
2292
+ ] })
2179
2293
  ] }),
2180
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: () => setIsModalOpen(true), children: [
2181
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
2182
- "เพิ่มช่วงราคา"
2294
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2295
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2296
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ประเภทขนส่ง" }),
2297
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "บริการ" }),
2298
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "น้ำหนัก ≤ (kg)" }),
2299
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
2300
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ETA" }),
2301
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
2302
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
2303
+ ] }) }),
2304
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredRates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลอัตราค่าขนส่ง" }) }) : filteredRates.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2305
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getCarrierLabel(rate.carrier_type) }),
2306
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: getServiceLabel(rate.service_code) }),
2307
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
2308
+ "≤ ",
2309
+ rate.max_weight_kg,
2310
+ " kg"
2311
+ ] }),
2312
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: rate.price.toFixed(2) }),
2313
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: formatETA(rate) }) }),
2314
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
2315
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
2316
+ /* @__PURE__ */ jsxRuntime.jsx(
2317
+ ui.Button,
2318
+ {
2319
+ variant: "transparent",
2320
+ size: "small",
2321
+ onClick: () => handleEdit(rate),
2322
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
2323
+ }
2324
+ ),
2325
+ /* @__PURE__ */ jsxRuntime.jsx(
2326
+ ui.Button,
2327
+ {
2328
+ variant: "transparent",
2329
+ size: "small",
2330
+ onClick: () => setDeleteRateId(rate.id),
2331
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
2332
+ }
2333
+ )
2334
+ ] }) })
2335
+ ] }, rate.id)) })
2183
2336
  ] })
2184
2337
  ] }),
2185
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { className: "mt-4", children: [
2186
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2187
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ช่วงระยะทาง" }),
2188
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
2189
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ลำดับ" }),
2190
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
2191
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
2192
- ] }) }),
2193
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { colSpan: 5, className: "text-center", children: "กำลังโหลด..." }) }) : orderedRates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { colSpan: 5, className: "text-center", children: "ยังไม่ได้ตั้งค่าฐานราคาตามระยะทาง (รถบริษัทจะใช้ราคาตามน้ำหนัก)" }) }) : orderedRates.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2194
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: formatDistanceRange(rate) }),
2195
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
2196
- "฿",
2197
- rate.price.toFixed(2)
2198
- ] }),
2199
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: rate.priority ?? 0 }),
2200
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
2201
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
2202
- /* @__PURE__ */ jsxRuntime.jsx(
2203
- ui.Button,
2204
- {
2205
- variant: "transparent",
2206
- size: "small",
2207
- onClick: () => {
2208
- setEditingRate(rate);
2209
- setIsModalOpen(true);
2210
- },
2211
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
2212
- }
2213
- ),
2214
- /* @__PURE__ */ jsxRuntime.jsx(
2215
- ui.Button,
2216
- {
2217
- variant: "transparent",
2218
- size: "small",
2219
- onClick: () => setDeleteId(rate.id),
2220
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
2221
- }
2222
- )
2223
- ] }) })
2224
- ] }, rate.id)) })
2225
- ] }),
2226
- isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(CompanyTruckBaseRateModal, { rate: editingRate, onClose: handleModalClose }),
2338
+ isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ShippingRateModal, { rate: editingRate, onClose: handleModalClose }),
2227
2339
  /* @__PURE__ */ jsxRuntime.jsx(
2228
2340
  ui.Prompt,
2229
2341
  {
2230
2342
  variant: "confirmation",
2231
- open: !!deleteId,
2232
- onOpenChange: () => setDeleteId(null),
2343
+ open: !!deleteRateId,
2344
+ onOpenChange: () => setDeleteRateId(null),
2233
2345
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
2234
2346
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
2235
- /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบฐานราคา" }),
2236
- /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: "คุณต้องการลบช่วงราคานี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
2347
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบอัตราค่าขนส่ง" }),
2348
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: "คุณต้องการลบอัตราค่าขนส่งนี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
2237
2349
  ] }),
2238
2350
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [
2239
2351
  /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: "ยกเลิก" }),
@@ -2244,71 +2356,49 @@ const CompanyTruckBasePricingTable = () => {
2244
2356
  )
2245
2357
  ] });
2246
2358
  };
2247
- const RatesPage = () => {
2248
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-8", children: [
2249
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "อัตราค่าขนส่ง" }) }),
2250
- /* @__PURE__ */ jsxRuntime.jsx(ShippingRatesTable, {}),
2251
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-4", children: [
2252
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-2 text-lg", children: "ฐานราคาตามระยะทาง (Messenger 3H)" }),
2253
- /* @__PURE__ */ jsxRuntime.jsx(MessengerBasePricingTable, {})
2254
- ] }),
2255
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-4", children: [
2256
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-2 text-lg", children: "ฐานราคาตามระยะทาง (รถบริษัท - Same Day)" }),
2257
- /* @__PURE__ */ jsxRuntime.jsx(CompanyTruckBasePricingTable, {})
2258
- ] })
2259
- ] }) });
2260
- };
2261
- const config$1 = adminSdk.defineRouteConfig({
2262
- icon: icons.HandTruck,
2263
- label: "อัตราค่าขนส่ง"
2264
- });
2265
- const CATEGORIES$1 = [
2266
- { value: "PACKAGING", label: "วัสดุหีบห่อ" },
2267
- { value: "PROTECTION", label: "วัสดุป้องกัน" },
2268
- { value: "FILLING", label: "วัสดุเติมช่องว่าง" },
2269
- { value: "TAPE", label: "เทป/กาว" },
2270
- { value: "LABEL", label: "ฉลาก/สติกเกอร์" },
2271
- { value: "OTHER", label: "อื่นๆ" }
2272
- ];
2273
- const MaterialCostModal = ({
2274
- materialCost,
2359
+ const CompanyTruckBaseRateModal = ({
2360
+ rate,
2275
2361
  onClose
2276
2362
  }) => {
2277
2363
  const [formData, setFormData] = react.useState({
2278
- name: "",
2279
- unit: "",
2280
- cost_per_unit: "",
2281
- currency: "THB",
2282
- category: "",
2283
- description: "",
2364
+ min_distance_km: "0",
2365
+ max_distance_km: "",
2366
+ price: "",
2367
+ priority: "0",
2284
2368
  active: true
2285
2369
  });
2286
2370
  const [isSaving, setIsSaving] = react.useState(false);
2287
2371
  react.useEffect(() => {
2288
- if (materialCost) {
2372
+ var _a, _b;
2373
+ if (rate) {
2289
2374
  setFormData({
2290
- name: materialCost.name,
2291
- unit: materialCost.unit,
2292
- cost_per_unit: materialCost.cost_per_unit.toString(),
2293
- currency: materialCost.currency,
2294
- category: materialCost.category || "",
2295
- description: materialCost.description || "",
2296
- active: materialCost.active
2375
+ min_distance_km: ((_a = rate.min_distance_km) == null ? void 0 : _a.toString()) ?? "0",
2376
+ max_distance_km: ((_b = rate.max_distance_km) == null ? void 0 : _b.toString()) || "",
2377
+ price: rate.price.toString(),
2378
+ priority: (rate.priority ?? 0).toString(),
2379
+ active: rate.active
2297
2380
  });
2298
2381
  }
2299
- }, [materialCost]);
2382
+ }, [rate]);
2300
2383
  const handleSubmit = async (e) => {
2301
2384
  e.preventDefault();
2302
2385
  const errors = [];
2303
- if (!formData.name.trim()) {
2304
- errors.push("กรุณากรอกชื่อวัสดุ");
2386
+ const minDistance = parseFloat(formData.min_distance_km || "0");
2387
+ const hasMaxDistance = formData.max_distance_km !== "";
2388
+ const maxDistance = hasMaxDistance ? parseFloat(formData.max_distance_km) : void 0;
2389
+ const price = parseFloat(formData.price);
2390
+ const priority = parseInt(formData.priority || "0", 10);
2391
+ if (isNaN(minDistance) || minDistance < 0) {
2392
+ errors.push("ระยะทางเริ่มต้นต้องไม่ติดลบ");
2305
2393
  }
2306
- if (!formData.unit.trim()) {
2307
- errors.push("กรุณากรอกหน่วย");
2394
+ if (hasMaxDistance && (maxDistance === void 0 || isNaN(maxDistance) || (maxDistance ?? 0) < minDistance)) {
2395
+ errors.push("ระยะทางสูงสุดต้องมากกว่าหรือเท่ากับระยะทางเริ่มต้น");
2308
2396
  }
2309
- const costPerUnit = parseFloat(formData.cost_per_unit);
2310
- if (isNaN(costPerUnit) || costPerUnit < 0) {
2311
- errors.push("ต้นทุนต่อหน่วยต้องเป็นตัวเลขไม่ติดลบ");
2397
+ if (isNaN(price) || price < 0) {
2398
+ errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
2399
+ }
2400
+ if (isNaN(priority)) {
2401
+ errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
2312
2402
  }
2313
2403
  if (errors.length > 0) {
2314
2404
  ui.toast.error("ข้อมูลไม่ถูกต้อง", {
@@ -2319,31 +2409,32 @@ const MaterialCostModal = ({
2319
2409
  setIsSaving(true);
2320
2410
  try {
2321
2411
  const payload = {
2322
- name: formData.name.trim(),
2323
- unit: formData.unit.trim(),
2324
- cost_per_unit: costPerUnit,
2325
- currency: formData.currency,
2326
- category: formData.category || void 0,
2327
- description: formData.description.trim() || void 0,
2412
+ carrier_type: "COMPANY_TRUCK",
2413
+ carrier: "COMPANY_TRUCK",
2414
+ service_code: "SAME_DAY",
2415
+ min_distance_km: minDistance,
2416
+ max_distance_km: maxDistance === void 0 || isNaN(maxDistance) ? null : maxDistance,
2417
+ price,
2418
+ currency: "THB",
2419
+ priority,
2328
2420
  active: formData.active
2329
2421
  };
2330
- const url = materialCost ? `/admin/material-costs/${materialCost.id}` : "/admin/material-costs";
2331
- const method = materialCost ? "PUT" : "POST";
2422
+ const url = rate ? `/admin/base-shipping-prices/${rate.id}` : "/admin/base-shipping-prices";
2423
+ const method = rate ? "PUT" : "POST";
2332
2424
  const response = await fetch(url, {
2333
2425
  method,
2334
2426
  headers: { "Content-Type": "application/json" },
2335
2427
  credentials: "include",
2336
2428
  body: JSON.stringify(payload)
2337
2429
  });
2338
- if (response.ok) {
2339
- ui.toast.success("สำเร็จ", {
2340
- description: materialCost ? "แก้ไขรายการต้นทุนวัสดุแล้ว" : "สร้างรายการต้นทุนวัสดุใหม่แล้ว"
2341
- });
2342
- onClose();
2343
- } else {
2344
- const error = await response.json();
2345
- throw new Error(error.message || "Failed to save");
2430
+ if (!response.ok) {
2431
+ const error = await response.json().catch(() => ({}));
2432
+ throw new Error(error.message || "ไม่สามารถบันทึกข้อมูลได้");
2346
2433
  }
2434
+ ui.toast.success("สำเร็จ", {
2435
+ description: rate ? "แก้ไขฐานราคาตามระยะทางแล้ว" : "สร้างฐานราคาตามระยะทางใหม่แล้ว"
2436
+ });
2437
+ onClose();
2347
2438
  } catch (error) {
2348
2439
  ui.toast.error("ข้อผิดพลาด", {
2349
2440
  description: error instanceof Error ? error.message : "ไม่สามารถบันทึกข้อมูลได้"
@@ -2353,89 +2444,69 @@ const MaterialCostModal = ({
2353
2444
  }
2354
2445
  };
2355
2446
  return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
2356
- /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: materialCost ? "แก้ไขรายการต้นทุนวัสดุ" : "สร้างรายการต้นทุนวัสดุใหม่" }) }),
2447
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { children: rate ? "แก้ไขฐานราคาตามระยะทาง (รถบริษัท)" : "สร้างฐานราคาตามระยะทาง (รถบริษัท)" }) }),
2357
2448
  /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
2358
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2359
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "name", children: "ชื่อวัสดุ *" }),
2360
- /* @__PURE__ */ jsxRuntime.jsx(
2361
- ui.Input,
2362
- {
2363
- id: "name",
2364
- value: formData.name,
2365
- onChange: (e) => setFormData({ ...formData, name: e.target.value }),
2366
- placeholder: "เช่น พลาสติกกันกระแทก, กล่องกระดาษ",
2367
- required: true
2368
- }
2369
- )
2370
- ] }),
2371
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2372
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "category", children: "หมวดหมู่ (ไม่บังคับ)" }),
2373
- /* @__PURE__ */ jsxRuntime.jsxs(
2374
- ui.Select,
2375
- {
2376
- value: formData.category || void 0,
2377
- onValueChange: (value) => setFormData({ ...formData, category: value }),
2378
- children: [
2379
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "เลือกหมวดหมู่ (ไม่บังคับ)" }) }),
2380
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES$1.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
2381
- ]
2382
- }
2383
- )
2384
- ] }),
2385
2449
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
2386
2450
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2387
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "unit", children: "หน่วย *" }),
2451
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "min_distance_km", children: "ระยะทางเริ่มต้น (กม.) *" }),
2388
2452
  /* @__PURE__ */ jsxRuntime.jsx(
2389
2453
  ui.Input,
2390
2454
  {
2391
- id: "unit",
2392
- value: formData.unit,
2393
- onChange: (e) => setFormData({ ...formData, unit: e.target.value }),
2394
- placeholder: "เช่น ชิ้น, เมตร, กิโลกรัม",
2455
+ id: "min_distance_km",
2456
+ type: "number",
2457
+ min: "0",
2458
+ step: "0.1",
2459
+ value: formData.min_distance_km,
2460
+ onChange: (e) => setFormData({ ...formData, min_distance_km: e.target.value }),
2395
2461
  required: true
2396
2462
  }
2397
2463
  )
2398
2464
  ] }),
2399
2465
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2400
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "costPerUnit", children: "ต้นทุนต่อหน่วย *" }),
2466
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "max_distance_km", children: "ระยะทางสูงสุด (กม.)" }),
2401
2467
  /* @__PURE__ */ jsxRuntime.jsx(
2402
2468
  ui.Input,
2403
2469
  {
2404
- id: "costPerUnit",
2470
+ id: "max_distance_km",
2405
2471
  type: "number",
2406
- step: "0.01",
2407
- value: formData.cost_per_unit,
2408
- onChange: (e) => setFormData({ ...formData, cost_per_unit: e.target.value }),
2409
- placeholder: "0.00",
2410
- required: true
2472
+ min: "0",
2473
+ step: "0.1",
2474
+ placeholder: "ปล่อยว่างหากไม่มีที่สิ้นสุด",
2475
+ value: formData.max_distance_km,
2476
+ onChange: (e) => setFormData({ ...formData, max_distance_km: e.target.value })
2411
2477
  }
2412
- )
2478
+ ),
2479
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "เว้นว่างเพื่อกำหนดช่วงราคาแบบ 30+ กม." })
2413
2480
  ] })
2414
2481
  ] }),
2415
2482
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2416
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "currency", children: "สกุลเงิน" }),
2483
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "price", children: "ราคา (THB) *" }),
2417
2484
  /* @__PURE__ */ jsxRuntime.jsx(
2418
2485
  ui.Input,
2419
2486
  {
2420
- id: "currency",
2421
- value: formData.currency,
2422
- onChange: (e) => setFormData({ ...formData, currency: e.target.value }),
2423
- placeholder: "THB"
2487
+ id: "price",
2488
+ type: "number",
2489
+ min: "0",
2490
+ step: "0.01",
2491
+ value: formData.price,
2492
+ onChange: (e) => setFormData({ ...formData, price: e.target.value }),
2493
+ required: true
2424
2494
  }
2425
2495
  )
2426
2496
  ] }),
2427
2497
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2428
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "description", children: "คำอธิบาย" }),
2498
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
2429
2499
  /* @__PURE__ */ jsxRuntime.jsx(
2430
- ui.Textarea,
2500
+ ui.Input,
2431
2501
  {
2432
- id: "description",
2433
- value: formData.description,
2434
- onChange: (e) => setFormData({ ...formData, description: e.target.value }),
2435
- placeholder: "คำอธิบายเพิ่มเติมเกี่ยวกับวัสดุนี้...",
2436
- rows: 3
2502
+ id: "priority",
2503
+ type: "number",
2504
+ value: formData.priority,
2505
+ onChange: (e) => setFormData({ ...formData, priority: e.target.value }),
2506
+ placeholder: "0"
2437
2507
  }
2438
- )
2508
+ ),
2509
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ใช้สำหรับจัดลำดับเมื่อมีช่วงราคาทับกัน (ค่าเริ่มต้น 0)" })
2439
2510
  ] }),
2440
2511
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
2441
2512
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2464,227 +2535,148 @@ const MaterialCostModal = ({
2464
2535
  ] }) })
2465
2536
  ] }) });
2466
2537
  };
2467
- const CATEGORIES = [
2468
- { value: "ALL", label: "ทั้งหมด" },
2469
- { value: "PACKAGING", label: "วัสดุหีบห่อ" },
2470
- { value: "PROTECTION", label: "วัสดุป้องกัน" },
2471
- { value: "FILLING", label: "วัสดุเติมช่องว่าง" },
2472
- { value: "TAPE", label: "เทป/กาว" },
2473
- { value: "LABEL", label: "ฉลาก/สติกเกอร์" },
2474
- { value: "OTHER", label: "อื่นๆ" }
2475
- ];
2476
- const MaterialCostsTable = () => {
2477
- const [materialCosts, setMaterialCosts] = react.useState([]);
2478
- const [filteredMaterialCosts, setFilteredMaterialCosts] = react.useState([]);
2479
- const [searchTerm, setSearchTerm] = react.useState("");
2480
- const [categoryFilter, setCategoryFilter] = react.useState("ALL");
2481
- const [isModalOpen, setIsModalOpen] = react.useState(false);
2482
- const [editingMaterialCost, setEditingMaterialCost] = react.useState(null);
2538
+ const CompanyTruckBasePricingTable = () => {
2539
+ const [rates, setRates] = react.useState([]);
2483
2540
  const [isLoading, setIsLoading] = react.useState(false);
2484
- const [deleteMaterialCostId, setDeleteMaterialCostId] = react.useState(null);
2485
- const [deleteMaterialCostName, setDeleteMaterialCostName] = react.useState("");
2541
+ const [isModalOpen, setIsModalOpen] = react.useState(false);
2542
+ const [editingRate, setEditingRate] = react.useState(null);
2543
+ const [deleteId, setDeleteId] = react.useState(null);
2486
2544
  react.useEffect(() => {
2487
- fetchMaterialCosts();
2545
+ fetchRates();
2488
2546
  }, []);
2489
- react.useEffect(() => {
2490
- let filtered = materialCosts;
2491
- if (categoryFilter !== "ALL") {
2492
- filtered = filtered.filter((mc) => mc.category === categoryFilter);
2493
- }
2494
- if (searchTerm) {
2495
- filtered = filtered.filter(
2496
- (mc) => mc.name.toLowerCase().includes(searchTerm.toLowerCase())
2497
- );
2498
- }
2499
- setFilteredMaterialCosts(filtered);
2500
- }, [searchTerm, categoryFilter, materialCosts]);
2501
- const fetchMaterialCosts = async () => {
2547
+ const orderedRates = react.useMemo(() => {
2548
+ return [...rates].sort((a, b) => {
2549
+ if (a.min_distance_km !== b.min_distance_km) {
2550
+ return a.min_distance_km - b.min_distance_km;
2551
+ }
2552
+ const aMax = a.max_distance_km ?? Number.POSITIVE_INFINITY;
2553
+ const bMax = b.max_distance_km ?? Number.POSITIVE_INFINITY;
2554
+ return aMax - bMax;
2555
+ });
2556
+ }, [rates]);
2557
+ const fetchRates = async () => {
2502
2558
  setIsLoading(true);
2503
- try {
2504
- const response = await fetch("/admin/material-costs", {
2505
- credentials: "include"
2506
- });
2559
+ try {
2560
+ const response = await fetch(
2561
+ "/admin/base-shipping-prices?carrier_type=COMPANY_TRUCK&service_code=SAME_DAY",
2562
+ {
2563
+ credentials: "include"
2564
+ }
2565
+ );
2566
+ if (!response.ok) {
2567
+ throw new Error("failed_to_load_base_rates");
2568
+ }
2507
2569
  const data = await response.json();
2508
- setMaterialCosts(data.material_costs || []);
2570
+ setRates(data.base_rates || []);
2509
2571
  } catch (error) {
2510
2572
  ui.toast.error("ข้อผิดพลาด", {
2511
- description: "ไม่สามารถโหลดข้อมูลต้นทุนวัสดุได้"
2573
+ description: "ไม่สามารถโหลดฐานราคาตามระยะทางได้"
2512
2574
  });
2513
2575
  } finally {
2514
2576
  setIsLoading(false);
2515
2577
  }
2516
2578
  };
2517
- const handleToggleActive = async (materialCost) => {
2518
- try {
2519
- const response = await fetch(`/admin/material-costs/${materialCost.id}`, {
2520
- method: "PUT",
2521
- headers: { "Content-Type": "application/json" },
2522
- credentials: "include",
2523
- body: JSON.stringify({ ...materialCost, active: !materialCost.active })
2524
- });
2525
- if (response.ok) {
2526
- ui.toast.success("สำเร็จ", {
2527
- description: `${materialCost.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}วัสดุ ${materialCost.name} แล้ว`
2528
- });
2529
- fetchMaterialCosts();
2530
- } else {
2531
- throw new Error("Failed to update");
2532
- }
2533
- } catch (error) {
2534
- ui.toast.error("ข้อผิดพลาด", {
2535
- description: "ไม่สามารถอัพเดทสถานะได้"
2536
- });
2537
- }
2538
- };
2539
2579
  const handleDelete = async () => {
2540
- if (!deleteMaterialCostId) return;
2580
+ if (!deleteId) return;
2541
2581
  try {
2542
2582
  const response = await fetch(
2543
- `/admin/material-costs/${deleteMaterialCostId}`,
2583
+ `/admin/base-shipping-prices/${deleteId}`,
2544
2584
  {
2545
2585
  method: "DELETE",
2546
2586
  credentials: "include"
2547
2587
  }
2548
2588
  );
2549
- if (response.ok) {
2550
- ui.toast.success("สำเร็จ", {
2551
- description: `ลบวัสดุ ${deleteMaterialCostName} แล้ว`
2552
- });
2553
- fetchMaterialCosts();
2554
- } else {
2555
- throw new Error("Failed to delete");
2589
+ if (!response.ok) {
2590
+ throw new Error("failed_to_delete");
2556
2591
  }
2592
+ ui.toast.success("สำเร็จ", {
2593
+ description: "ลบฐานราคาสำเร็จ"
2594
+ });
2595
+ fetchRates();
2557
2596
  } catch (error) {
2558
2597
  ui.toast.error("ข้อผิดพลาด", {
2559
- description: "ไม่สามารถลบวัสดุได้"
2598
+ description: "ไม่สามารถลบฐานราคาได้"
2560
2599
  });
2561
2600
  } finally {
2562
- setDeleteMaterialCostId(null);
2563
- setDeleteMaterialCostName("");
2601
+ setDeleteId(null);
2564
2602
  }
2565
2603
  };
2566
- const handleEdit = (materialCost) => {
2567
- setEditingMaterialCost(materialCost);
2568
- setIsModalOpen(true);
2569
- };
2570
- const handleCreateNew = () => {
2571
- setEditingMaterialCost(null);
2572
- setIsModalOpen(true);
2573
- };
2574
2604
  const handleModalClose = () => {
2575
2605
  setIsModalOpen(false);
2576
- setEditingMaterialCost(null);
2577
- fetchMaterialCosts();
2578
- };
2579
- const openDeletePrompt = (id, name) => {
2580
- setDeleteMaterialCostId(id);
2581
- setDeleteMaterialCostName(name);
2606
+ setEditingRate(null);
2607
+ fetchRates();
2582
2608
  };
2583
- const getCategoryLabel = (category) => {
2584
- var _a;
2585
- if (!category) return "-";
2586
- return ((_a = CATEGORIES.find((c) => c.value === category)) == null ? void 0 : _a.label) || category;
2609
+ const formatDistanceRange = (rate) => {
2610
+ const min = rate.min_distance_km ?? 0;
2611
+ const max = rate.max_distance_km;
2612
+ if (max === void 0 || max === null) {
2613
+ return `${min}+ กม.`;
2614
+ }
2615
+ return `${min}-${max} กม.`;
2587
2616
  };
2588
2617
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2589
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
2590
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
2591
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4 flex-1", children: [
2618
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
2619
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2620
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold", children: "ฐานราคาตามระยะทาง (รถบริษัท - Same Day)" }),
2621
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-ui-fg-subtle text-sm", children: "กำหนดราคาเริ่มต้นตามระยะทาง เช่น 0-10, 10-30, 30-50, 50+ กม." })
2622
+ ] }),
2623
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: () => setIsModalOpen(true), children: [
2624
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
2625
+ "เพิ่มช่วงราคา"
2626
+ ] })
2627
+ ] }),
2628
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { className: "mt-4", children: [
2629
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2630
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ช่วงระยะทาง" }),
2631
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ราคา (THB)" }),
2632
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ลำดับ" }),
2633
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
2634
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
2635
+ ] }) }),
2636
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { colSpan: 5, className: "text-center", children: "กำลังโหลด..." }) }) : orderedRates.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { colSpan: 5, className: "text-center", children: "ยังไม่ได้ตั้งค่าฐานราคาตามระยะทาง (รถบริษัทจะใช้ราคาตามน้ำหนัก)" }) }) : orderedRates.map((rate) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2637
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: formatDistanceRange(rate) }),
2638
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
2639
+ "฿",
2640
+ rate.price.toFixed(2)
2641
+ ] }),
2642
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: rate.priority ?? 0 }),
2643
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
2644
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
2592
2645
  /* @__PURE__ */ jsxRuntime.jsx(
2593
- ui.Input,
2646
+ ui.Button,
2594
2647
  {
2595
- type: "search",
2596
- placeholder: "ค้นหาชื่อวัสดุ...",
2597
- value: searchTerm,
2598
- onChange: (e) => setSearchTerm(e.target.value),
2599
- className: "max-w-md"
2648
+ variant: "transparent",
2649
+ size: "small",
2650
+ onClick: () => {
2651
+ setEditingRate(rate);
2652
+ setIsModalOpen(true);
2653
+ },
2654
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
2600
2655
  }
2601
2656
  ),
2602
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: categoryFilter, onValueChange: setCategoryFilter, children: [
2603
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder: "หมวดหมู่" }) }),
2604
- /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: CATEGORIES.map((category) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: category.value, children: category.label }, category.value)) })
2605
- ] })
2606
- ] }),
2607
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { onClick: handleCreateNew, children: [
2608
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, {}),
2609
- "สร้างรายการใหม่"
2610
- ] })
2611
- ] }),
2612
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2613
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2614
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ชื่อ" }),
2615
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หมวดหมู่" }),
2616
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "หน่วย" }),
2617
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "ต้นทุนต่อหน่วย" }),
2618
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "คำอธิบาย" }),
2619
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: "สถานะ" }),
2620
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
2621
- ] }) }),
2622
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : filteredMaterialCosts.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-center", children: "ไม่พบข้อมูลต้นทุนวัสดุ" }) }) : filteredMaterialCosts.map((materialCost) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2623
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.name }),
2624
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { color: "blue", children: getCategoryLabel(materialCost.category) }) }),
2625
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: materialCost.unit }),
2626
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { children: [
2627
- materialCost.cost_per_unit.toFixed(2),
2628
- " ",
2629
- materialCost.currency
2630
- ] }),
2631
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-xs truncate", children: materialCost.description || "-" }),
2632
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
2633
- ui.Badge,
2657
+ /* @__PURE__ */ jsxRuntime.jsx(
2658
+ ui.Button,
2634
2659
  {
2635
- color: materialCost.active ? "green" : "grey",
2636
- className: "cursor-pointer",
2637
- onClick: () => handleToggleActive(materialCost),
2638
- children: materialCost.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
2660
+ variant: "transparent",
2661
+ size: "small",
2662
+ onClick: () => setDeleteId(rate.id),
2663
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
2639
2664
  }
2640
- ) }),
2641
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
2642
- /* @__PURE__ */ jsxRuntime.jsx(
2643
- ui.Button,
2644
- {
2645
- variant: "transparent",
2646
- size: "small",
2647
- onClick: () => handleEdit(materialCost),
2648
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Edit, {})
2649
- }
2650
- ),
2651
- /* @__PURE__ */ jsxRuntime.jsx(
2652
- ui.Button,
2653
- {
2654
- variant: "transparent",
2655
- size: "small",
2656
- onClick: () => openDeletePrompt(materialCost.id, materialCost.name),
2657
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash, {})
2658
- }
2659
- )
2660
- ] }) })
2661
- ] }, materialCost.id)) })
2662
- ] })
2665
+ )
2666
+ ] }) })
2667
+ ] }, rate.id)) })
2663
2668
  ] }),
2664
- isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(
2665
- MaterialCostModal,
2666
- {
2667
- materialCost: editingMaterialCost,
2668
- onClose: handleModalClose
2669
- }
2670
- ),
2669
+ isModalOpen && /* @__PURE__ */ jsxRuntime.jsx(CompanyTruckBaseRateModal, { rate: editingRate, onClose: handleModalClose }),
2671
2670
  /* @__PURE__ */ jsxRuntime.jsx(
2672
2671
  ui.Prompt,
2673
2672
  {
2674
2673
  variant: "confirmation",
2675
- open: !!deleteMaterialCostId,
2676
- onOpenChange: () => {
2677
- setDeleteMaterialCostId(null);
2678
- setDeleteMaterialCostName("");
2679
- },
2674
+ open: !!deleteId,
2675
+ onOpenChange: () => setDeleteId(null),
2680
2676
  children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [
2681
2677
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [
2682
- /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบรายการต้นทุนวัสดุ" }),
2683
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Description, { children: [
2684
- 'คุณต้องการลบวัสดุ "',
2685
- deleteMaterialCostName,
2686
- '" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
2687
- ] })
2678
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: "ลบฐานราคา" }),
2679
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: "คุณต้องการลบช่วงราคานี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
2688
2680
  ] }),
2689
2681
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [
2690
2682
  /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: "ยกเลิก" }),
@@ -2695,15 +2687,23 @@ const MaterialCostsTable = () => {
2695
2687
  )
2696
2688
  ] });
2697
2689
  };
2698
- const MaterialCostsPage = () => {
2699
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [
2700
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "ต้นทุนวัสดุ" }) }),
2701
- /* @__PURE__ */ jsxRuntime.jsx(MaterialCostsTable, {})
2690
+ const RatesPage = () => {
2691
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-8", children: [
2692
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: "อัตราค่าขนส่ง" }) }),
2693
+ /* @__PURE__ */ jsxRuntime.jsx(ShippingRatesTable, {}),
2694
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-4", children: [
2695
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-2 text-lg", children: "ฐานราคาตามระยะทาง (Messenger 3H)" }),
2696
+ /* @__PURE__ */ jsxRuntime.jsx(MessengerBasePricingTable, {})
2697
+ ] }),
2698
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-4", children: [
2699
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", className: "mb-2 text-lg", children: "ฐานราคาตามระยะทาง (รถบริษัท - Same Day)" }),
2700
+ /* @__PURE__ */ jsxRuntime.jsx(CompanyTruckBasePricingTable, {})
2701
+ ] })
2702
2702
  ] }) });
2703
2703
  };
2704
2704
  const config = adminSdk.defineRouteConfig({
2705
- icon: icons.CurrencyDollarSolid,
2706
- label: "ต้นทุนวัสดุ"
2705
+ icon: icons.HandTruck,
2706
+ label: "อัตราค่าขนส่ง"
2707
2707
  });
2708
2708
  const widgetModule = { widgets: [
2709
2709
  {
@@ -2725,13 +2725,13 @@ const routeModule = {
2725
2725
  Component: BoxesPage,
2726
2726
  path: "/boxes"
2727
2727
  },
2728
- {
2729
- Component: RatesPage,
2730
- path: "/rates"
2731
- },
2732
2728
  {
2733
2729
  Component: MaterialCostsPage,
2734
2730
  path: "/material-costs"
2731
+ },
2732
+ {
2733
+ Component: RatesPage,
2734
+ path: "/rates"
2735
2735
  }
2736
2736
  ]
2737
2737
  };
@@ -2762,16 +2762,16 @@ const menuItemModule = {
2762
2762
  translationNs: void 0
2763
2763
  },
2764
2764
  {
2765
- label: config.label,
2766
- icon: config.icon,
2765
+ label: config$1.label,
2766
+ icon: config$1.icon,
2767
2767
  path: "/material-costs",
2768
2768
  nested: void 0,
2769
2769
  rank: void 0,
2770
2770
  translationNs: void 0
2771
2771
  },
2772
2772
  {
2773
- label: config$1.label,
2774
- icon: config$1.icon,
2773
+ label: config.label,
2774
+ icon: config.icon,
2775
2775
  path: "/rates",
2776
2776
  nested: void 0,
2777
2777
  rank: void 0,