@lodashventure/medusa-parcel-shipping 0.4.29 → 0.4.31

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