@lodashventure/medusa-parcel-shipping 0.4.7 → 0.4.8

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