@lodashventure/medusa-parcel-shipping 0.4.24 → 0.4.26

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, useMemo } from "react";
5
5
  import { Package, AlertCircle, Truck, Clock, Plus, Edit, Trash, ExternalLink } from "lucide-react";
6
- import { MapPin, Route, ArchiveBox, CurrencyDollarSolid, HandTruck } from "@medusajs/icons";
6
+ import { Directions, ArchiveBox, MapPin, CurrencyDollarSolid, HandTruck } from "@medusajs/icons";
7
7
  import "@medusajs/admin-shared";
8
8
  const OrderShippingQuoteWidget = ({ data }) => {
9
9
  const [quote, setQuote] = useState(null);
@@ -235,116 +235,49 @@ const OrderShippingQuoteWidget = ({ data }) => {
235
235
  defineWidgetConfig({
236
236
  zone: "order.details.after"
237
237
  });
238
- const TH_PROVINCES = [
239
- "กรุงเทพมหานคร",
240
- "กระบี่",
241
- "กาญจนบุรี",
242
- "กาฬสินธุ์",
243
- "กำแพงเพชร",
244
- "ขอนแก่น",
245
- "จันทบุรี",
246
- "ฉะเชิงเทรา",
247
- "ชลบุรี",
248
- "ชัยนาท",
249
- "ชัยภูมิ",
250
- "ชุมพร",
251
- "เชียงราย",
252
- "เชียงใหม่",
253
- "ตรัง",
254
- "ตราด",
255
- "ตาก",
256
- "นครนายก",
257
- "นครปฐม",
258
- "นครพนม",
259
- "นครราชสีมา",
260
- "นครศรีธรรมราช",
261
- "นครสวรรค์",
262
- "นนทบุรี",
263
- "นราธิวาส",
264
- "น่าน",
265
- "บึงกาฬ",
266
- "บุรีรัมย์",
267
- "ปทุมธานี",
268
- "ประจวบคีรีขันธ์",
269
- "ปราจีนบุรี",
270
- "ปัตตานี",
271
- "พระนครศรีอยุธยา",
272
- "พะเยา",
273
- "พังงา",
274
- "พัทลุง",
275
- "พิจิตร",
276
- "พิษณุโลก",
277
- "เพชรบุรี",
278
- "เพชรบูรณ์",
279
- "แพร่",
280
- "ภูเก็ต",
281
- "มหาสารคาม",
282
- "มุกดาหาร",
283
- "แม่ฮ่องสอน",
284
- "ยโสธร",
285
- "ยะลา",
286
- "ร้อยเอ็ด",
287
- "ระนอง",
288
- "ระยอง",
289
- "ราชบุรี",
290
- "ลพบุรี",
291
- "ลำปาง",
292
- "ลำพูน",
293
- "เลย",
294
- "ศรีสะเกษ",
295
- "สกลนคร",
296
- "สงขลา",
297
- "สตูล",
298
- "สมุทรปราการ",
299
- "สมุทรสงคราม",
300
- "สมุทรสาคร",
301
- "สระแก้ว",
302
- "สระบุรี",
303
- "สิงห์บุรี",
304
- "สุโขทัย",
305
- "สุพรรณบุรี",
306
- "สุราษฎร์ธานี",
307
- "สุรินทร์",
308
- "หนองคาย",
309
- "หนองบัวลำภู",
310
- "อ่างทอง",
311
- "อำนาจเจริญ",
312
- "อุดรธานี",
313
- "อุตรดิตถ์",
314
- "อุทัยธานี",
315
- "อุบลราชธานี"
316
- ];
317
- const ServiceAreaModal = ({ area, onClose }) => {
238
+ const MessengerBaseRateModal = ({
239
+ rate,
240
+ onClose
241
+ }) => {
318
242
  const [formData, setFormData] = useState({
319
- kind: "PROVINCE",
320
- value: "",
243
+ min_distance_km: "0",
244
+ max_distance_km: "",
245
+ price: "",
246
+ priority: "0",
321
247
  active: true
322
248
  });
323
249
  const [isSaving, setIsSaving] = useState(false);
324
250
  useEffect(() => {
325
- if (area) {
251
+ var _a, _b;
252
+ if (rate) {
326
253
  setFormData({
327
- kind: area.kind,
328
- value: area.value,
329
- active: area.active
254
+ min_distance_km: ((_a = rate.min_distance_km) == null ? void 0 : _a.toString()) ?? "0",
255
+ max_distance_km: ((_b = rate.max_distance_km) == null ? void 0 : _b.toString()) || "",
256
+ price: rate.price.toString(),
257
+ priority: (rate.priority ?? 0).toString(),
258
+ active: rate.active
330
259
  });
331
260
  }
332
- }, [area]);
261
+ }, [rate]);
333
262
  const handleSubmit = async (e) => {
334
263
  e.preventDefault();
335
264
  const errors = [];
336
- const trimmedValue = formData.value.trim();
337
- if (!trimmedValue) {
338
- errors.push("กรุณากรอกค่า");
265
+ const minDistance = parseFloat(formData.min_distance_km || "0");
266
+ const hasMaxDistance = formData.max_distance_km !== "";
267
+ const maxDistance = hasMaxDistance ? parseFloat(formData.max_distance_km) : void 0;
268
+ const price = parseFloat(formData.price);
269
+ const priority = parseInt(formData.priority || "0", 10);
270
+ if (isNaN(minDistance) || minDistance < 0) {
271
+ errors.push("ระยะทางเริ่มต้นต้องไม่ติดลบ");
339
272
  }
340
- if (formData.kind === "PROVINCE") {
341
- if (!TH_PROVINCES.includes(trimmedValue)) {
342
- errors.push("จังหวัดไม่ถูกต้อง กรุณาตรวจสอบการสะกดชื่อจังหวัด");
343
- }
344
- } else if (formData.kind === "POSTCODE_PREFIX") {
345
- if (!/^\d{1,5}$/.test(trimmedValue)) {
346
- errors.push("รหัสไปรษณีย์ต้องเป็นตัวเลข 1-5 หลัก");
347
- }
273
+ if (hasMaxDistance && (maxDistance === void 0 || isNaN(maxDistance) || (maxDistance ?? 0) < minDistance)) {
274
+ errors.push("ระยะทางสูงสุดต้องมากกว่าหรือเท่ากับระยะทางเริ่มต้น");
275
+ }
276
+ if (isNaN(price) || price < 0) {
277
+ errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
278
+ }
279
+ if (isNaN(priority)) {
280
+ errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
348
281
  }
349
282
  if (errors.length > 0) {
350
283
  toast.error("ข้อมูลไม่ถูกต้อง", {
@@ -355,27 +288,32 @@ const ServiceAreaModal = ({ area, onClose }) => {
355
288
  setIsSaving(true);
356
289
  try {
357
290
  const payload = {
358
- kind: formData.kind,
359
- value: trimmedValue,
291
+ carrier_type: "COMPANY_FLEET",
292
+ carrier: "COMPANY_FLEET",
293
+ service_code: "MESSENGER_3H",
294
+ min_distance_km: minDistance,
295
+ max_distance_km: maxDistance === void 0 || isNaN(maxDistance) ? null : maxDistance,
296
+ price,
297
+ currency: "THB",
298
+ priority,
360
299
  active: formData.active
361
300
  };
362
- const url = area ? `/admin/service-areas/${area.id}` : "/admin/service-areas";
363
- const method = area ? "PUT" : "POST";
301
+ const url = rate ? `/admin/base-shipping-prices/${rate.id}` : "/admin/base-shipping-prices";
302
+ const method = rate ? "PUT" : "POST";
364
303
  const response = await fetch(url, {
365
304
  method,
366
305
  headers: { "Content-Type": "application/json" },
367
306
  credentials: "include",
368
307
  body: JSON.stringify(payload)
369
308
  });
370
- if (response.ok) {
371
- toast.success("สำเร็จ", {
372
- description: area ? "แก้ไขพื้นที่บริการแล้ว" : "สร้างพื้นที่บริการใหม่แล้ว"
373
- });
374
- onClose();
375
- } else {
376
- const error = await response.json();
377
- throw new Error(error.message || "Failed to save");
309
+ if (!response.ok) {
310
+ const error = await response.json().catch(() => ({}));
311
+ throw new Error(error.message || "ไม่สามารถบันทึกข้อมูลได้");
378
312
  }
313
+ toast.success("สำเร็จ", {
314
+ description: rate ? "แก้ไขฐานราคาตามระยะทางแล้ว" : "สร้างฐานราคาตามระยะทางใหม่แล้ว"
315
+ });
316
+ onClose();
379
317
  } catch (error) {
380
318
  toast.error("ข้อผิดพลาด", {
381
319
  description: error instanceof Error ? error.message : "ไม่สามารถบันทึกข้อมูลได้"
@@ -385,53 +323,69 @@ const ServiceAreaModal = ({ area, onClose }) => {
385
323
  }
386
324
  };
387
325
  return /* @__PURE__ */ jsx(Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
388
- /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: area ? "แก้ไขพื้นที่บริการ" : "สร้างพื้นที่บริการใหม่" }) }),
326
+ /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: rate ? "แก้ไขฐานราคาตามระยะทาง" : "สร้างฐานราคาตามระยะทาง" }) }),
389
327
  /* @__PURE__ */ jsx(Drawer.Body, { children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
328
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
329
+ /* @__PURE__ */ jsxs("div", { children: [
330
+ /* @__PURE__ */ jsx(Label, { htmlFor: "min_distance_km", children: "ระยะทางเริ่มต้น (กม.) *" }),
331
+ /* @__PURE__ */ jsx(
332
+ Input,
333
+ {
334
+ id: "min_distance_km",
335
+ type: "number",
336
+ min: "0",
337
+ step: "0.1",
338
+ value: formData.min_distance_km,
339
+ onChange: (e) => setFormData({ ...formData, min_distance_km: e.target.value }),
340
+ required: true
341
+ }
342
+ )
343
+ ] }),
344
+ /* @__PURE__ */ jsxs("div", { children: [
345
+ /* @__PURE__ */ jsx(Label, { htmlFor: "max_distance_km", children: "ระยะทางสูงสุด (กม.)" }),
346
+ /* @__PURE__ */ jsx(
347
+ Input,
348
+ {
349
+ id: "max_distance_km",
350
+ type: "number",
351
+ min: "0",
352
+ step: "0.1",
353
+ placeholder: "ปล่อยว่างหากไม่มีที่สิ้นสุด",
354
+ value: formData.max_distance_km,
355
+ onChange: (e) => setFormData({ ...formData, max_distance_km: e.target.value })
356
+ }
357
+ ),
358
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "เว้นว่างเพื่อกำหนดช่วงราคาแบบ 30+ กม." })
359
+ ] })
360
+ ] }),
390
361
  /* @__PURE__ */ jsxs("div", { children: [
391
- /* @__PURE__ */ jsx(Label, { htmlFor: "kind", children: "ประเภท *" }),
392
- /* @__PURE__ */ jsxs(
393
- Select,
362
+ /* @__PURE__ */ jsx(Label, { htmlFor: "price", children: "ราคา (THB) *" }),
363
+ /* @__PURE__ */ jsx(
364
+ Input,
394
365
  {
395
- value: formData.kind,
396
- onValueChange: (value) => setFormData({ ...formData, kind: value, value: "" }),
397
- required: true,
398
- children: [
399
- /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "เลือกประเภท" }) }),
400
- /* @__PURE__ */ jsxs(Select.Content, { children: [
401
- /* @__PURE__ */ jsx(Select.Item, { value: "PROVINCE", children: "จังหวัด" }),
402
- /* @__PURE__ */ jsx(Select.Item, { value: "POSTCODE_PREFIX", children: "รหัสไปรษณีย์" })
403
- ] })
404
- ]
366
+ id: "price",
367
+ type: "number",
368
+ min: "0",
369
+ step: "0.01",
370
+ value: formData.price,
371
+ onChange: (e) => setFormData({ ...formData, price: e.target.value }),
372
+ required: true
405
373
  }
406
374
  )
407
375
  ] }),
408
376
  /* @__PURE__ */ jsxs("div", { children: [
409
- /* @__PURE__ */ jsx(Label, { htmlFor: "value", children: formData.kind === "PROVINCE" ? "ชื่อจังหวัด *" : "รหัสไปรษณีย์ (1-5 หลัก) *" }),
410
- formData.kind === "PROVINCE" ? /* @__PURE__ */ jsxs(
411
- Select,
412
- {
413
- value: formData.value,
414
- onValueChange: (value) => setFormData({ ...formData, value }),
415
- required: true,
416
- children: [
417
- /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "เลือกจังหวัด" }) }),
418
- /* @__PURE__ */ jsx(Select.Content, { children: TH_PROVINCES.map((province) => /* @__PURE__ */ jsx(Select.Item, { value: province, children: province }, province)) })
419
- ]
420
- }
421
- ) : /* @__PURE__ */ jsx(
377
+ /* @__PURE__ */ jsx(Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
378
+ /* @__PURE__ */ jsx(
422
379
  Input,
423
380
  {
424
- id: "value",
425
- type: "text",
426
- value: formData.value,
427
- onChange: (e) => setFormData({ ...formData, value: e.target.value }),
428
- placeholder: "เช่น 10, 102, 10200",
429
- maxLength: 5,
430
- pattern: "\\d{1,5}",
431
- required: true
381
+ id: "priority",
382
+ type: "number",
383
+ value: formData.priority,
384
+ onChange: (e) => setFormData({ ...formData, priority: e.target.value }),
385
+ placeholder: "0"
432
386
  }
433
387
  ),
434
- formData.kind === "POSTCODE_PREFIX" && /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: 'ใส่รหัส 1-5 หลักเพื่อครอบคลุมหลายพื้นที่ เช่น "10" = กรุงเทพฯ ทั้งหมด' })
388
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ใช้สำหรับจัดลำดับเมื่อมีช่วงราคาทับกัน (ค่าเริ่มต้น 0)" })
435
389
  ] }),
436
390
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
437
391
  /* @__PURE__ */ jsx(
@@ -460,200 +414,148 @@ const ServiceAreaModal = ({ area, onClose }) => {
460
414
  ] }) })
461
415
  ] }) });
462
416
  };
463
- const AREA_KINDS = [
464
- { value: "ALL", label: "ทั้งหมด" },
465
- { value: "PROVINCE", label: "จังหวัด" },
466
- { value: "POSTCODE_PREFIX", label: "รหัสไปรษณีย์" }
467
- ];
468
- const ServiceAreasTable = () => {
469
- const [areas, setAreas] = useState([]);
470
- const [filteredAreas, setFilteredAreas] = useState([]);
471
- const [searchTerm, setSearchTerm] = useState("");
472
- const [kindFilter, setKindFilter] = useState("ALL");
473
- const [isModalOpen, setIsModalOpen] = useState(false);
474
- const [editingArea, setEditingArea] = useState(null);
417
+ const MessengerBasePricingTable = () => {
418
+ const [rates, setRates] = useState([]);
475
419
  const [isLoading, setIsLoading] = useState(false);
476
- const [deleteAreaId, setDeleteAreaId] = useState(null);
477
- const [deleteAreaValue, setDeleteAreaValue] = useState("");
420
+ const [isModalOpen, setIsModalOpen] = useState(false);
421
+ const [editingRate, setEditingRate] = useState(null);
422
+ const [deleteId, setDeleteId] = useState(null);
478
423
  useEffect(() => {
479
- fetchAreas();
424
+ fetchRates();
480
425
  }, []);
481
- useEffect(() => {
482
- let filtered = areas;
483
- if (kindFilter !== "ALL") {
484
- filtered = filtered.filter((area) => area.kind === kindFilter);
485
- }
486
- if (searchTerm) {
487
- filtered = filtered.filter(
488
- (area) => area.value.toLowerCase().includes(searchTerm.toLowerCase())
489
- );
490
- }
491
- setFilteredAreas(filtered);
492
- }, [searchTerm, kindFilter, areas]);
493
- const fetchAreas = async () => {
426
+ const orderedRates = useMemo(() => {
427
+ return [...rates].sort((a, b) => {
428
+ if (a.min_distance_km !== b.min_distance_km) {
429
+ return a.min_distance_km - b.min_distance_km;
430
+ }
431
+ const aMax = a.max_distance_km ?? Number.POSITIVE_INFINITY;
432
+ const bMax = b.max_distance_km ?? Number.POSITIVE_INFINITY;
433
+ return aMax - bMax;
434
+ });
435
+ }, [rates]);
436
+ const fetchRates = async () => {
494
437
  setIsLoading(true);
495
438
  try {
496
- const response = await fetch("/admin/service-areas", {
497
- credentials: "include"
498
- });
439
+ const response = await fetch(
440
+ "/admin/base-shipping-prices?carrier_type=COMPANY_FLEET&service_code=MESSENGER_3H",
441
+ {
442
+ credentials: "include"
443
+ }
444
+ );
445
+ if (!response.ok) {
446
+ throw new Error("failed_to_load_base_rates");
447
+ }
499
448
  const data = await response.json();
500
- console.log("Fetched service areas:", data);
501
- setAreas(data.service_areas || []);
449
+ setRates(data.base_rates || []);
502
450
  } catch (error) {
503
451
  toast.error("ข้อผิดพลาด", {
504
- description: "ไม่สามารถโหลดข้อมูลพื้นที่บริการได้"
452
+ description: "ไม่สามารถโหลดฐานราคาตามระยะทางได้"
505
453
  });
506
454
  } finally {
507
455
  setIsLoading(false);
508
456
  }
509
457
  };
510
- const handleToggleActive = async (area) => {
511
- try {
512
- const response = await fetch(`/admin/service-areas/${area.id}`, {
513
- method: "PUT",
514
- headers: { "Content-Type": "application/json" },
515
- credentials: "include",
516
- body: JSON.stringify({ ...area, active: !area.active })
517
- });
518
- if (response.ok) {
519
- toast.success("สำเร็จ", {
520
- description: `${area.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}พื้นที่ ${area.value} แล้ว`
521
- });
522
- fetchAreas();
523
- } else {
524
- throw new Error("Failed to update");
525
- }
526
- } catch (error) {
527
- toast.error("ข้อผิดพลาด", {
528
- description: "ไม่สามารถอัพเดทสถานะได้"
529
- });
530
- }
531
- };
532
458
  const handleDelete = async () => {
533
- if (!deleteAreaId) return;
459
+ if (!deleteId) return;
534
460
  try {
535
- const response = await fetch(`/admin/service-areas/${deleteAreaId}`, {
536
- method: "DELETE",
537
- credentials: "include"
538
- });
539
- if (response.ok) {
540
- toast.success("สำเร็จ", {
541
- description: `ลบพื้นที่ ${deleteAreaValue} แล้ว`
542
- });
543
- fetchAreas();
544
- } else {
545
- throw new Error("Failed to delete");
461
+ const response = await fetch(
462
+ `/admin/base-shipping-prices/${deleteId}`,
463
+ {
464
+ method: "DELETE",
465
+ credentials: "include"
466
+ }
467
+ );
468
+ if (!response.ok) {
469
+ throw new Error("failed_to_delete");
546
470
  }
471
+ toast.success("สำเร็จ", {
472
+ description: "ลบฐานราคาสำเร็จ"
473
+ });
474
+ fetchRates();
547
475
  } catch (error) {
548
476
  toast.error("ข้อผิดพลาด", {
549
- description: "ไม่สามารถลบพื้นที่ได้"
477
+ description: "ไม่สามารถลบฐานราคาได้"
550
478
  });
551
479
  } finally {
552
- setDeleteAreaId(null);
553
- setDeleteAreaValue("");
480
+ setDeleteId(null);
554
481
  }
555
482
  };
556
- const handleEdit = (area) => {
557
- setEditingArea(area);
558
- setIsModalOpen(true);
559
- };
560
- const handleCreateNew = () => {
561
- setEditingArea(null);
562
- setIsModalOpen(true);
563
- };
564
483
  const handleModalClose = () => {
565
484
  setIsModalOpen(false);
566
- setEditingArea(null);
567
- fetchAreas();
485
+ setEditingRate(null);
486
+ fetchRates();
568
487
  };
569
- const openDeletePrompt = (id, value) => {
570
- setDeleteAreaId(id);
571
- setDeleteAreaValue(value);
488
+ const formatDistanceRange = (rate) => {
489
+ const min = rate.min_distance_km ?? 0;
490
+ const max = rate.max_distance_km;
491
+ if (max === void 0 || max === null) {
492
+ return `${min}+ กม.`;
493
+ }
494
+ return `${min}-${max} กม.`;
572
495
  };
573
496
  return /* @__PURE__ */ jsxs(Fragment, { children: [
574
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
575
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
576
- /* @__PURE__ */ jsxs("div", { className: "flex gap-x-4 flex-1", children: [
497
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
498
+ /* @__PURE__ */ jsxs("div", { children: [
499
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "ฐานราคาตามระยะทาง (Messenger 3H)" }),
500
+ /* @__PURE__ */ jsx("p", { className: "text-ui-fg-subtle text-sm", children: "กำหนดราคาเริ่มต้นตามระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม." })
501
+ ] }),
502
+ /* @__PURE__ */ jsxs(Button, { onClick: () => setIsModalOpen(true), children: [
503
+ /* @__PURE__ */ jsx(Plus, {}),
504
+ "เพิ่มช่วงราคา"
505
+ ] })
506
+ ] }),
507
+ /* @__PURE__ */ jsxs(Table, { className: "mt-4", children: [
508
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
509
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ช่วงระยะทาง" }),
510
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ราคา (THB)" }),
511
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ลำดับ" }),
512
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "สถานะ" }),
513
+ /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
514
+ ] }) }),
515
+ /* @__PURE__ */ jsx(Table.Body, { children: isLoading ? /* @__PURE__ */ jsx(Table.Row, { children: /* @__PURE__ */ jsx(Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : orderedRates.length === 0 ? /* @__PURE__ */ jsx(Table.Row, { children: /* @__PURE__ */ jsx(Table.Cell, { className: "text-center", children: "ยังไม่ได้ตั้งค่าฐานราคาตามระยะทาง" }) }) : orderedRates.map((rate) => /* @__PURE__ */ jsxs(Table.Row, { children: [
516
+ /* @__PURE__ */ jsx(Table.Cell, { children: formatDistanceRange(rate) }),
517
+ /* @__PURE__ */ jsxs(Table.Cell, { children: [
518
+ "฿",
519
+ rate.price.toFixed(2)
520
+ ] }),
521
+ /* @__PURE__ */ jsx(Table.Cell, { children: rate.priority ?? 0 }),
522
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
523
+ /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
577
524
  /* @__PURE__ */ jsx(
578
- Input,
525
+ Button,
579
526
  {
580
- type: "search",
581
- placeholder: "ค้นหาจังหวัดหรือรหัสไปรษณีย์...",
582
- value: searchTerm,
583
- onChange: (e) => setSearchTerm(e.target.value),
584
- className: "max-w-md"
527
+ variant: "transparent",
528
+ size: "small",
529
+ onClick: () => {
530
+ setEditingRate(rate);
531
+ setIsModalOpen(true);
532
+ },
533
+ children: /* @__PURE__ */ jsx(Edit, {})
585
534
  }
586
535
  ),
587
- /* @__PURE__ */ jsxs(Select, { value: kindFilter, onValueChange: setKindFilter, children: [
588
- /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "ประเภท" }) }),
589
- /* @__PURE__ */ jsx(Select.Content, { children: AREA_KINDS.map((kind) => /* @__PURE__ */ jsx(Select.Item, { value: kind.value, children: kind.label }, kind.value)) })
590
- ] })
591
- ] }),
592
- /* @__PURE__ */ jsxs(Button, { onClick: handleCreateNew, children: [
593
- /* @__PURE__ */ jsx(Plus, {}),
594
- "สร้างพื้นที่ใหม่"
595
- ] })
596
- ] }),
597
- /* @__PURE__ */ jsxs(Table, { children: [
598
- /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
599
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ประเภท" }),
600
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ค่า" }),
601
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "สถานะ" }),
602
- /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
603
- ] }) }),
604
- /* @__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: [
605
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: area.kind === "PROVINCE" ? "blue" : "purple", children: area.kind === "PROVINCE" ? "จังหวัด" : "รหัสไปรษณีย์" }) }),
606
- /* @__PURE__ */ jsx(Table.Cell, { children: area.value }),
607
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
608
- Badge,
536
+ /* @__PURE__ */ jsx(
537
+ Button,
609
538
  {
610
- color: area.active ? "green" : "grey",
611
- className: "cursor-pointer",
612
- onClick: () => handleToggleActive(area),
613
- children: area.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
539
+ variant: "transparent",
540
+ size: "small",
541
+ onClick: () => setDeleteId(rate.id),
542
+ children: /* @__PURE__ */ jsx(Trash, {})
614
543
  }
615
- ) }),
616
- /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
617
- /* @__PURE__ */ jsx(
618
- Button,
619
- {
620
- variant: "transparent",
621
- size: "small",
622
- onClick: () => handleEdit(area),
623
- children: /* @__PURE__ */ jsx(Edit, {})
624
- }
625
- ),
626
- /* @__PURE__ */ jsx(
627
- Button,
628
- {
629
- variant: "transparent",
630
- size: "small",
631
- onClick: () => openDeletePrompt(area.id, area.value),
632
- children: /* @__PURE__ */ jsx(Trash, {})
633
- }
634
- )
635
- ] }) })
636
- ] }, area.id)) })
637
- ] })
544
+ )
545
+ ] }) })
546
+ ] }, rate.id)) })
638
547
  ] }),
639
- isModalOpen && /* @__PURE__ */ jsx(ServiceAreaModal, { area: editingArea, onClose: handleModalClose }),
548
+ isModalOpen && /* @__PURE__ */ jsx(MessengerBaseRateModal, { rate: editingRate, onClose: handleModalClose }),
640
549
  /* @__PURE__ */ jsx(
641
550
  Prompt,
642
551
  {
643
552
  variant: "confirmation",
644
- open: !!deleteAreaId,
645
- onOpenChange: () => {
646
- setDeleteAreaId(null);
647
- setDeleteAreaValue("");
648
- },
553
+ open: !!deleteId,
554
+ onOpenChange: () => setDeleteId(null),
649
555
  children: /* @__PURE__ */ jsxs(Prompt.Content, { children: [
650
556
  /* @__PURE__ */ jsxs(Prompt.Header, { children: [
651
- /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบพื้นที่บริการ" }),
652
- /* @__PURE__ */ jsxs(Prompt.Description, { children: [
653
- 'คุณต้องการลบพื้นที่ "',
654
- deleteAreaValue,
655
- '" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
656
- ] })
557
+ /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบฐานราคา" }),
558
+ /* @__PURE__ */ jsx(Prompt.Description, { children: "คุณต้องการลบช่วงราคานี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
657
559
  ] }),
658
560
  /* @__PURE__ */ jsxs(Prompt.Footer, { children: [
659
561
  /* @__PURE__ */ jsx(Prompt.Cancel, { children: "ยกเลิก" }),
@@ -664,60 +566,69 @@ const ServiceAreasTable = () => {
664
566
  )
665
567
  ] });
666
568
  };
667
- const AreasPage = () => {
668
- return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
669
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "พื้นที่บริการ" }) }),
670
- /* @__PURE__ */ jsx(ServiceAreasTable, {})
569
+ const BasePricingPage = () => {
570
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
571
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
572
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "ฐานราคาตามระยะทาง (Messenger)" }),
573
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "ตั้งราคาฐานสำหรับบริการ Messenger 3 ชั่วโมงตามช่วงระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม." })
574
+ ] }),
575
+ /* @__PURE__ */ jsx(MessengerBasePricingTable, {})
671
576
  ] }) });
672
577
  };
673
578
  const config$4 = defineRouteConfig({
674
- icon: MapPin,
675
- label: "พื้นที่บริการ"
579
+ icon: Directions,
580
+ label: "ฐานราคาตามระยะทาง"
676
581
  });
677
- const MessengerBaseRateModal = ({
678
- rate,
679
- onClose
680
- }) => {
582
+ const ParcelBoxModal = ({ box, onClose }) => {
681
583
  const [formData, setFormData] = useState({
682
- min_distance_km: "0",
683
- max_distance_km: "",
684
- price: "",
685
- priority: "0",
584
+ name: "",
585
+ width_cm: "",
586
+ length_cm: "",
587
+ height_cm: "",
588
+ max_weight_kg: "",
589
+ price_thb: "",
686
590
  active: true
687
591
  });
688
592
  const [isSaving, setIsSaving] = useState(false);
689
593
  useEffect(() => {
690
- var _a, _b;
691
- if (rate) {
594
+ if (box) {
692
595
  setFormData({
693
- min_distance_km: ((_a = rate.min_distance_km) == null ? void 0 : _a.toString()) ?? "0",
694
- max_distance_km: ((_b = rate.max_distance_km) == null ? void 0 : _b.toString()) || "",
695
- price: rate.price.toString(),
696
- priority: (rate.priority ?? 0).toString(),
697
- active: rate.active
596
+ name: box.name,
597
+ width_cm: box.width_cm.toString(),
598
+ length_cm: box.length_cm.toString(),
599
+ height_cm: box.height_cm.toString(),
600
+ max_weight_kg: box.max_weight_kg.toString(),
601
+ price_thb: box.price_thb.toString(),
602
+ active: box.active
698
603
  });
699
604
  }
700
- }, [rate]);
605
+ }, [box]);
701
606
  const handleSubmit = async (e) => {
702
607
  e.preventDefault();
703
608
  const errors = [];
704
- const minDistance = parseFloat(formData.min_distance_km || "0");
705
- const hasMaxDistance = formData.max_distance_km !== "";
706
- const maxDistance = hasMaxDistance ? parseFloat(formData.max_distance_km) : void 0;
707
- const price = parseFloat(formData.price);
708
- const priority = parseInt(formData.priority || "0", 10);
709
- if (isNaN(minDistance) || minDistance < 0) {
710
- errors.push("ระยะทางเริ่มต้นต้องไม่ติดลบ");
609
+ if (!formData.name.trim()) {
610
+ errors.push("กรุณากรอกชื่อกล่อง");
711
611
  }
712
- if (hasMaxDistance && (maxDistance === void 0 || isNaN(maxDistance) || (maxDistance ?? 0) < minDistance)) {
713
- errors.push("ระยะทางสูงสุดต้องมากกว่าหรือเท่ากับระยะทางเริ่มต้น");
612
+ const width = parseFloat(formData.width_cm);
613
+ const length = parseFloat(formData.length_cm);
614
+ const height = parseFloat(formData.height_cm);
615
+ const maxWeight = parseFloat(formData.max_weight_kg);
616
+ const price = parseFloat(formData.price_thb);
617
+ if (isNaN(width) || width <= 0) {
618
+ errors.push("ความกว้างต้องเป็นตัวเลขมากกว่า 0");
619
+ }
620
+ if (isNaN(length) || length <= 0) {
621
+ errors.push("ความยาวต้องเป็นตัวเลขมากกว่า 0");
622
+ }
623
+ if (isNaN(height) || height <= 0) {
624
+ errors.push("ความสูงต้องเป็นตัวเลขมากกว่า 0");
625
+ }
626
+ if (isNaN(maxWeight) || maxWeight <= 0) {
627
+ errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
714
628
  }
715
629
  if (isNaN(price) || price < 0) {
716
630
  errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
717
631
  }
718
- if (isNaN(priority)) {
719
- errors.push("ลำดับความสำคัญต้องเป็นตัวเลข");
720
- }
721
632
  if (errors.length > 0) {
722
633
  toast.error("ข้อมูลไม่ถูกต้อง", {
723
634
  description: errors.join(", ")
@@ -727,32 +638,31 @@ const MessengerBaseRateModal = ({
727
638
  setIsSaving(true);
728
639
  try {
729
640
  const payload = {
730
- carrier_type: "COMPANY_FLEET",
731
- carrier: "COMPANY_FLEET",
732
- service_code: "MESSENGER_3H",
733
- min_distance_km: minDistance,
734
- max_distance_km: maxDistance === void 0 || isNaN(maxDistance) ? null : maxDistance,
735
- price,
736
- currency: "THB",
737
- priority,
641
+ name: formData.name.trim(),
642
+ width_cm: width,
643
+ length_cm: length,
644
+ height_cm: height,
645
+ max_weight_kg: maxWeight,
646
+ price_thb: price,
738
647
  active: formData.active
739
648
  };
740
- const url = rate ? `/admin/base-shipping-prices/${rate.id}` : "/admin/base-shipping-prices";
741
- const method = rate ? "PUT" : "POST";
649
+ const url = box ? `/admin/boxes/${box.id}` : "/admin/boxes";
650
+ const method = box ? "PUT" : "POST";
742
651
  const response = await fetch(url, {
743
652
  method,
744
653
  headers: { "Content-Type": "application/json" },
745
654
  credentials: "include",
746
655
  body: JSON.stringify(payload)
747
656
  });
748
- if (!response.ok) {
749
- const error = await response.json().catch(() => ({}));
750
- throw new Error(error.message || "ไม่สามารถบันทึกข้อมูลได้");
657
+ if (response.ok) {
658
+ toast.success("สำเร็จ", {
659
+ description: box ? "แก้ไขกล่องพัสดุแล้ว" : "สร้างกล่องพัสดุใหม่แล้ว"
660
+ });
661
+ onClose();
662
+ } else {
663
+ const error = await response.json();
664
+ throw new Error(error.message || "Failed to save");
751
665
  }
752
- toast.success("สำเร็จ", {
753
- description: rate ? "แก้ไขฐานราคาตามระยะทางแล้ว" : "สร้างฐานราคาตามระยะทางใหม่แล้ว"
754
- });
755
- onClose();
756
666
  } catch (error) {
757
667
  toast.error("ข้อผิดพลาด", {
758
668
  description: error instanceof Error ? error.message : "ไม่สามารถบันทึกข้อมูลได้"
@@ -762,69 +672,97 @@ const MessengerBaseRateModal = ({
762
672
  }
763
673
  };
764
674
  return /* @__PURE__ */ jsx(Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
765
- /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: rate ? "แก้ไขฐานราคาตามระยะทาง" : "สร้างฐานราคาตามระยะทาง" }) }),
675
+ /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: box ? "แก้ไขกล่องพัสดุ" : "สร้างกล่องพัสดุใหม่" }) }),
766
676
  /* @__PURE__ */ jsx(Drawer.Body, { children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
767
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-x-4", children: [
677
+ /* @__PURE__ */ jsxs("div", { children: [
678
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "ชื่อกล่อง *" }),
679
+ /* @__PURE__ */ jsx(
680
+ Input,
681
+ {
682
+ id: "name",
683
+ value: formData.name,
684
+ onChange: (e) => setFormData({ ...formData, name: e.target.value }),
685
+ placeholder: "เช่น กล่อง S, กล่อง M",
686
+ required: true
687
+ }
688
+ )
689
+ ] }),
690
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-x-4", children: [
768
691
  /* @__PURE__ */ jsxs("div", { children: [
769
- /* @__PURE__ */ jsx(Label, { htmlFor: "min_distance_km", children: "ระยะทางเริ่มต้น (กม.) *" }),
692
+ /* @__PURE__ */ jsx(Label, { htmlFor: "width", children: "ความกว้าง (cm) *" }),
770
693
  /* @__PURE__ */ jsx(
771
694
  Input,
772
695
  {
773
- id: "min_distance_km",
696
+ id: "width",
774
697
  type: "number",
775
- min: "0",
776
698
  step: "0.1",
777
- value: formData.min_distance_km,
778
- onChange: (e) => setFormData({ ...formData, min_distance_km: e.target.value }),
699
+ value: formData.width_cm,
700
+ onChange: (e) => setFormData({ ...formData, width_cm: e.target.value }),
701
+ placeholder: "20",
779
702
  required: true
780
703
  }
781
704
  )
782
705
  ] }),
783
706
  /* @__PURE__ */ jsxs("div", { children: [
784
- /* @__PURE__ */ jsx(Label, { htmlFor: "max_distance_km", children: "ระยะทางสูงสุด (กม.)" }),
707
+ /* @__PURE__ */ jsx(Label, { htmlFor: "length", children: "ความยาว (cm) *" }),
785
708
  /* @__PURE__ */ jsx(
786
709
  Input,
787
710
  {
788
- id: "max_distance_km",
711
+ id: "length",
789
712
  type: "number",
790
- min: "0",
791
713
  step: "0.1",
792
- placeholder: "ปล่อยว่างหากไม่มีที่สิ้นสุด",
793
- value: formData.max_distance_km,
794
- onChange: (e) => setFormData({ ...formData, max_distance_km: e.target.value })
714
+ value: formData.length_cm,
715
+ onChange: (e) => setFormData({ ...formData, length_cm: e.target.value }),
716
+ placeholder: "30",
717
+ required: true
795
718
  }
796
- ),
797
- /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "เว้นว่างเพื่อกำหนดช่วงราคาแบบ 30+ กม." })
719
+ )
720
+ ] }),
721
+ /* @__PURE__ */ jsxs("div", { children: [
722
+ /* @__PURE__ */ jsx(Label, { htmlFor: "height", children: "ความสูง (cm) *" }),
723
+ /* @__PURE__ */ jsx(
724
+ Input,
725
+ {
726
+ id: "height",
727
+ type: "number",
728
+ step: "0.1",
729
+ value: formData.height_cm,
730
+ onChange: (e) => setFormData({ ...formData, height_cm: e.target.value }),
731
+ placeholder: "15",
732
+ required: true
733
+ }
734
+ )
798
735
  ] })
799
736
  ] }),
800
737
  /* @__PURE__ */ jsxs("div", { children: [
801
- /* @__PURE__ */ jsx(Label, { htmlFor: "price", children: "ราคา (THB) *" }),
738
+ /* @__PURE__ */ jsx(Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
802
739
  /* @__PURE__ */ jsx(
803
740
  Input,
804
741
  {
805
- id: "price",
742
+ id: "maxWeight",
806
743
  type: "number",
807
- min: "0",
808
- step: "0.01",
809
- value: formData.price,
810
- onChange: (e) => setFormData({ ...formData, price: e.target.value }),
744
+ step: "0.1",
745
+ value: formData.max_weight_kg,
746
+ onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
747
+ placeholder: "0.5",
811
748
  required: true
812
749
  }
813
750
  )
814
751
  ] }),
815
752
  /* @__PURE__ */ jsxs("div", { children: [
816
- /* @__PURE__ */ jsx(Label, { htmlFor: "priority", children: "ลำดับความสำคัญ" }),
753
+ /* @__PURE__ */ jsx(Label, { htmlFor: "price", children: "ราคา (THB) *" }),
817
754
  /* @__PURE__ */ jsx(
818
755
  Input,
819
756
  {
820
- id: "priority",
757
+ id: "price",
821
758
  type: "number",
822
- value: formData.priority,
823
- onChange: (e) => setFormData({ ...formData, priority: e.target.value }),
824
- placeholder: "0"
759
+ step: "0.01",
760
+ value: formData.price_thb,
761
+ onChange: (e) => setFormData({ ...formData, price_thb: e.target.value }),
762
+ placeholder: "10.00",
763
+ required: true
825
764
  }
826
- ),
827
- /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: "ใช้สำหรับจัดลำดับเมื่อมีช่วงราคาทับกัน (ค่าเริ่มต้น 0)" })
765
+ )
828
766
  ] }),
829
767
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
830
768
  /* @__PURE__ */ jsx(
@@ -838,163 +776,197 @@ const MessengerBaseRateModal = ({
838
776
  /* @__PURE__ */ jsx(Label, { htmlFor: "active", children: "เปิดใช้งาน" })
839
777
  ] }),
840
778
  /* @__PURE__ */ jsxs(Drawer.Footer, { children: [
841
- /* @__PURE__ */ jsx(
842
- Button,
843
- {
844
- type: "button",
845
- variant: "secondary",
846
- onClick: onClose,
847
- disabled: isSaving,
848
- children: "ยกเลิก"
849
- }
850
- ),
779
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
851
780
  /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
852
781
  ] })
853
782
  ] }) })
854
783
  ] }) });
855
784
  };
856
- const MessengerBasePricingTable = () => {
857
- const [rates, setRates] = useState([]);
858
- const [isLoading, setIsLoading] = useState(false);
785
+ const ParcelBoxesTable = () => {
786
+ const [boxes, setBoxes] = useState([]);
787
+ const [filteredBoxes, setFilteredBoxes] = useState([]);
788
+ const [searchTerm, setSearchTerm] = useState("");
859
789
  const [isModalOpen, setIsModalOpen] = useState(false);
860
- const [editingRate, setEditingRate] = useState(null);
861
- const [deleteId, setDeleteId] = useState(null);
790
+ const [editingBox, setEditingBox] = useState(null);
791
+ const [isLoading, setIsLoading] = useState(false);
792
+ const [deleteBoxId, setDeleteBoxId] = useState(null);
793
+ const [deleteBoxName, setDeleteBoxName] = useState("");
862
794
  useEffect(() => {
863
- fetchRates();
795
+ fetchBoxes();
864
796
  }, []);
865
- const orderedRates = useMemo(() => {
866
- return [...rates].sort((a, b) => {
867
- if (a.min_distance_km !== b.min_distance_km) {
868
- return a.min_distance_km - b.min_distance_km;
869
- }
870
- const aMax = a.max_distance_km ?? Number.POSITIVE_INFINITY;
871
- const bMax = b.max_distance_km ?? Number.POSITIVE_INFINITY;
872
- return aMax - bMax;
873
- });
874
- }, [rates]);
875
- const fetchRates = async () => {
797
+ useEffect(() => {
798
+ const filtered = boxes.filter(
799
+ (box) => box.name.toLowerCase().includes(searchTerm.toLowerCase())
800
+ );
801
+ setFilteredBoxes(filtered);
802
+ }, [searchTerm, boxes]);
803
+ const fetchBoxes = async () => {
876
804
  setIsLoading(true);
877
805
  try {
878
- const response = await fetch(
879
- "/admin/base-shipping-prices?carrier_type=COMPANY_FLEET&service_code=MESSENGER_3H",
880
- {
881
- credentials: "include"
882
- }
883
- );
884
- if (!response.ok) {
885
- throw new Error("failed_to_load_base_rates");
886
- }
806
+ const response = await fetch("/admin/boxes", {
807
+ credentials: "include"
808
+ });
887
809
  const data = await response.json();
888
- setRates(data.base_rates || []);
810
+ setBoxes(data.boxes || []);
889
811
  } catch (error) {
890
812
  toast.error("ข้อผิดพลาด", {
891
- description: "ไม่สามารถโหลดฐานราคาตามระยะทางได้"
813
+ description: "ไม่สามารถโหลดข้อมูลกล่องพัสดุได้"
892
814
  });
893
815
  } finally {
894
816
  setIsLoading(false);
895
817
  }
896
818
  };
897
- const handleDelete = async () => {
898
- if (!deleteId) return;
819
+ const handleToggleActive = async (box) => {
899
820
  try {
900
- const response = await fetch(
901
- `/admin/base-shipping-prices/${deleteId}`,
902
- {
903
- method: "DELETE",
904
- credentials: "include"
905
- }
906
- );
907
- if (!response.ok) {
908
- throw new Error("failed_to_delete");
821
+ const response = await fetch(`/admin/boxes/${box.id}`, {
822
+ method: "PUT",
823
+ headers: { "Content-Type": "application/json" },
824
+ credentials: "include",
825
+ body: JSON.stringify({ ...box, active: !box.active })
826
+ });
827
+ if (response.ok) {
828
+ toast.success("สำเร็จ", {
829
+ description: `${box.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}กล่อง ${box.name} แล้ว`
830
+ });
831
+ fetchBoxes();
832
+ } else {
833
+ throw new Error("Failed to update");
909
834
  }
910
- toast.success("สำเร็จ", {
911
- description: "ลบฐานราคาสำเร็จ"
835
+ } catch (error) {
836
+ toast.error("ข้อผิดพลาด", {
837
+ description: "ไม่สามารถอัพเดทสถานะได้"
912
838
  });
913
- fetchRates();
839
+ }
840
+ };
841
+ const handleDelete = async () => {
842
+ if (!deleteBoxId) return;
843
+ try {
844
+ const response = await fetch(`/admin/boxes/${deleteBoxId}`, {
845
+ method: "DELETE",
846
+ credentials: "include"
847
+ });
848
+ if (response.ok) {
849
+ toast.success("สำเร็จ", {
850
+ description: `ลบกล่อง ${deleteBoxName} แล้ว`
851
+ });
852
+ fetchBoxes();
853
+ } else {
854
+ throw new Error("Failed to delete");
855
+ }
914
856
  } catch (error) {
915
857
  toast.error("ข้อผิดพลาด", {
916
- description: "ไม่สามารถลบฐานราคาได้"
858
+ description: "ไม่สามารถลบกล่องได้"
917
859
  });
918
860
  } finally {
919
- setDeleteId(null);
861
+ setDeleteBoxId(null);
862
+ setDeleteBoxName("");
920
863
  }
921
864
  };
865
+ const handleEdit = (box) => {
866
+ setEditingBox(box);
867
+ setIsModalOpen(true);
868
+ };
869
+ const handleCreateNew = () => {
870
+ setEditingBox(null);
871
+ setIsModalOpen(true);
872
+ };
922
873
  const handleModalClose = () => {
923
874
  setIsModalOpen(false);
924
- setEditingRate(null);
925
- fetchRates();
875
+ setEditingBox(null);
876
+ fetchBoxes();
926
877
  };
927
- const formatDistanceRange = (rate) => {
928
- const min = rate.min_distance_km ?? 0;
929
- const max = rate.max_distance_km;
930
- if (max === void 0 || max === null) {
931
- return `${min}+ กม.`;
932
- }
933
- return `${min}-${max} กม.`;
878
+ const openDeletePrompt = (id, name) => {
879
+ setDeleteBoxId(id);
880
+ setDeleteBoxName(name);
934
881
  };
935
882
  return /* @__PURE__ */ jsxs(Fragment, { children: [
936
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
937
- /* @__PURE__ */ jsxs("div", { children: [
938
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold", children: "ฐานราคาตามระยะทาง (Messenger 3H)" }),
939
- /* @__PURE__ */ jsx("p", { className: "text-ui-fg-subtle text-sm", children: "กำหนดราคาเริ่มต้นตามระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม." })
883
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
884
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
885
+ /* @__PURE__ */ jsx(
886
+ Input,
887
+ {
888
+ type: "search",
889
+ placeholder: "ค้นหาชื่อกล่อง...",
890
+ value: searchTerm,
891
+ onChange: (e) => setSearchTerm(e.target.value),
892
+ className: "max-w-md"
893
+ }
894
+ ),
895
+ /* @__PURE__ */ jsxs(Button, { onClick: handleCreateNew, children: [
896
+ /* @__PURE__ */ jsx(Plus, {}),
897
+ "สร้างกล่องใหม่"
898
+ ] })
940
899
  ] }),
941
- /* @__PURE__ */ jsxs(Button, { onClick: () => setIsModalOpen(true), children: [
942
- /* @__PURE__ */ jsx(Plus, {}),
943
- "เพิ่มช่วงราคา"
944
- ] })
945
- ] }),
946
- /* @__PURE__ */ jsxs(Table, { className: "mt-4", children: [
947
- /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
948
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ช่วงระยะทาง" }),
949
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ราคา (THB)" }),
950
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ลำดับ" }),
951
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "สถานะ" }),
952
- /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
953
- ] }) }),
954
- /* @__PURE__ */ jsx(Table.Body, { children: isLoading ? /* @__PURE__ */ jsx(Table.Row, { children: /* @__PURE__ */ jsx(Table.Cell, { className: "text-center", children: "กำลังโหลด..." }) }) : orderedRates.length === 0 ? /* @__PURE__ */ jsx(Table.Row, { children: /* @__PURE__ */ jsx(Table.Cell, { className: "text-center", children: "ยังไม่ได้ตั้งค่าฐานราคาตามระยะทาง" }) }) : orderedRates.map((rate) => /* @__PURE__ */ jsxs(Table.Row, { children: [
955
- /* @__PURE__ */ jsx(Table.Cell, { children: formatDistanceRange(rate) }),
956
- /* @__PURE__ */ jsxs(Table.Cell, { children: [
957
- "฿",
958
- rate.price.toFixed(2)
959
- ] }),
960
- /* @__PURE__ */ jsx(Table.Cell, { children: rate.priority ?? 0 }),
961
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: rate.active ? "green" : "grey", children: rate.active ? "เปิดใช้งาน" : "ปิดใช้งาน" }) }),
962
- /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
963
- /* @__PURE__ */ jsx(
964
- Button,
965
- {
966
- variant: "transparent",
967
- size: "small",
968
- onClick: () => {
969
- setEditingRate(rate);
970
- setIsModalOpen(true);
971
- },
972
- children: /* @__PURE__ */ jsx(Edit, {})
973
- }
974
- ),
975
- /* @__PURE__ */ jsx(
976
- Button,
900
+ /* @__PURE__ */ jsxs(Table, { children: [
901
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
902
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ชื่อ" }),
903
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ขนาด (กว้าง×ยาว×สูง cm)" }),
904
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "น้ำหนักสูงสุด (kg)" }),
905
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ราคา (THB)" }),
906
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "สถานะ" }),
907
+ /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
908
+ ] }) }),
909
+ /* @__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: [
910
+ /* @__PURE__ */ jsx(Table.Cell, { children: box.name }),
911
+ /* @__PURE__ */ jsxs(Table.Cell, { children: [
912
+ box.width_cm,
913
+ " × ",
914
+ box.length_cm,
915
+ " × ",
916
+ box.height_cm
917
+ ] }),
918
+ /* @__PURE__ */ jsx(Table.Cell, { children: box.max_weight_kg }),
919
+ /* @__PURE__ */ jsx(Table.Cell, { children: box.price_thb.toFixed(2) }),
920
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
921
+ Badge,
977
922
  {
978
- variant: "transparent",
979
- size: "small",
980
- onClick: () => setDeleteId(rate.id),
981
- children: /* @__PURE__ */ jsx(Trash, {})
923
+ color: box.active ? "green" : "grey",
924
+ className: "cursor-pointer",
925
+ onClick: () => handleToggleActive(box),
926
+ children: box.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
982
927
  }
983
- )
984
- ] }) })
985
- ] }, rate.id)) })
928
+ ) }),
929
+ /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
930
+ /* @__PURE__ */ jsx(
931
+ Button,
932
+ {
933
+ variant: "transparent",
934
+ size: "small",
935
+ onClick: () => handleEdit(box),
936
+ children: /* @__PURE__ */ jsx(Edit, {})
937
+ }
938
+ ),
939
+ /* @__PURE__ */ jsx(
940
+ Button,
941
+ {
942
+ variant: "transparent",
943
+ size: "small",
944
+ onClick: () => openDeletePrompt(box.id, box.name),
945
+ children: /* @__PURE__ */ jsx(Trash, {})
946
+ }
947
+ )
948
+ ] }) })
949
+ ] }, box.id)) })
950
+ ] })
986
951
  ] }),
987
- isModalOpen && /* @__PURE__ */ jsx(MessengerBaseRateModal, { rate: editingRate, onClose: handleModalClose }),
952
+ isModalOpen && /* @__PURE__ */ jsx(ParcelBoxModal, { box: editingBox, onClose: handleModalClose }),
988
953
  /* @__PURE__ */ jsx(
989
954
  Prompt,
990
955
  {
991
956
  variant: "confirmation",
992
- open: !!deleteId,
993
- onOpenChange: () => setDeleteId(null),
957
+ open: !!deleteBoxId,
958
+ onOpenChange: () => {
959
+ setDeleteBoxId(null);
960
+ setDeleteBoxName("");
961
+ },
994
962
  children: /* @__PURE__ */ jsxs(Prompt.Content, { children: [
995
963
  /* @__PURE__ */ jsxs(Prompt.Header, { children: [
996
- /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบฐานราคา" }),
997
- /* @__PURE__ */ jsx(Prompt.Description, { children: "คุณต้องการลบช่วงราคานี้ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้" })
964
+ /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบกล่องพัสดุ" }),
965
+ /* @__PURE__ */ jsxs(Prompt.Description, { children: [
966
+ 'คุณต้องการลบกล่อง "',
967
+ deleteBoxName,
968
+ '" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
969
+ ] })
998
970
  ] }),
999
971
  /* @__PURE__ */ jsxs(Prompt.Footer, { children: [
1000
972
  /* @__PURE__ */ jsx(Prompt.Cancel, { children: "ยกเลิก" }),
@@ -1005,68 +977,126 @@ const MessengerBasePricingTable = () => {
1005
977
  )
1006
978
  ] });
1007
979
  };
1008
- const BasePricingPage = () => {
1009
- return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-6", children: [
1010
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
1011
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "ฐานราคาตามระยะทาง (Messenger)" }),
1012
- /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: "ตั้งราคาฐานสำหรับบริการ Messenger 3 ชั่วโมงตามช่วงระยะทาง เช่น 0-5, 5-20, 20-30, 30+ กม." })
1013
- ] }),
1014
- /* @__PURE__ */ jsx(MessengerBasePricingTable, {})
980
+ const BoxesPage = () => {
981
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
982
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "กล่องพัสดุ" }) }),
983
+ /* @__PURE__ */ jsx(ParcelBoxesTable, {})
1015
984
  ] }) });
1016
985
  };
1017
986
  const config$3 = defineRouteConfig({
1018
- icon: Route,
1019
- label: "ฐานราคาตามระยะทาง"
987
+ icon: ArchiveBox,
988
+ label: "กล่องพัสดุ"
1020
989
  });
1021
- const ParcelBoxModal = ({ box, onClose }) => {
990
+ const TH_PROVINCES = [
991
+ "กรุงเทพมหานคร",
992
+ "กระบี่",
993
+ "กาญจนบุรี",
994
+ "กาฬสินธุ์",
995
+ "กำแพงเพชร",
996
+ "ขอนแก่น",
997
+ "จันทบุรี",
998
+ "ฉะเชิงเทรา",
999
+ "ชลบุรี",
1000
+ "ชัยนาท",
1001
+ "ชัยภูมิ",
1002
+ "ชุมพร",
1003
+ "เชียงราย",
1004
+ "เชียงใหม่",
1005
+ "ตรัง",
1006
+ "ตราด",
1007
+ "ตาก",
1008
+ "นครนายก",
1009
+ "นครปฐม",
1010
+ "นครพนม",
1011
+ "นครราชสีมา",
1012
+ "นครศรีธรรมราช",
1013
+ "นครสวรรค์",
1014
+ "นนทบุรี",
1015
+ "นราธิวาส",
1016
+ "น่าน",
1017
+ "บึงกาฬ",
1018
+ "บุรีรัมย์",
1019
+ "ปทุมธานี",
1020
+ "ประจวบคีรีขันธ์",
1021
+ "ปราจีนบุรี",
1022
+ "ปัตตานี",
1023
+ "พระนครศรีอยุธยา",
1024
+ "พะเยา",
1025
+ "พังงา",
1026
+ "พัทลุง",
1027
+ "พิจิตร",
1028
+ "พิษณุโลก",
1029
+ "เพชรบุรี",
1030
+ "เพชรบูรณ์",
1031
+ "แพร่",
1032
+ "ภูเก็ต",
1033
+ "มหาสารคาม",
1034
+ "มุกดาหาร",
1035
+ "แม่ฮ่องสอน",
1036
+ "ยโสธร",
1037
+ "ยะลา",
1038
+ "ร้อยเอ็ด",
1039
+ "ระนอง",
1040
+ "ระยอง",
1041
+ "ราชบุรี",
1042
+ "ลพบุรี",
1043
+ "ลำปาง",
1044
+ "ลำพูน",
1045
+ "เลย",
1046
+ "ศรีสะเกษ",
1047
+ "สกลนคร",
1048
+ "สงขลา",
1049
+ "สตูล",
1050
+ "สมุทรปราการ",
1051
+ "สมุทรสงคราม",
1052
+ "สมุทรสาคร",
1053
+ "สระแก้ว",
1054
+ "สระบุรี",
1055
+ "สิงห์บุรี",
1056
+ "สุโขทัย",
1057
+ "สุพรรณบุรี",
1058
+ "สุราษฎร์ธานี",
1059
+ "สุรินทร์",
1060
+ "หนองคาย",
1061
+ "หนองบัวลำภู",
1062
+ "อ่างทอง",
1063
+ "อำนาจเจริญ",
1064
+ "อุดรธานี",
1065
+ "อุตรดิตถ์",
1066
+ "อุทัยธานี",
1067
+ "อุบลราชธานี"
1068
+ ];
1069
+ const ServiceAreaModal = ({ area, onClose }) => {
1022
1070
  const [formData, setFormData] = useState({
1023
- name: "",
1024
- width_cm: "",
1025
- length_cm: "",
1026
- height_cm: "",
1027
- max_weight_kg: "",
1028
- price_thb: "",
1071
+ kind: "PROVINCE",
1072
+ value: "",
1029
1073
  active: true
1030
1074
  });
1031
1075
  const [isSaving, setIsSaving] = useState(false);
1032
1076
  useEffect(() => {
1033
- if (box) {
1077
+ if (area) {
1034
1078
  setFormData({
1035
- name: box.name,
1036
- width_cm: box.width_cm.toString(),
1037
- length_cm: box.length_cm.toString(),
1038
- height_cm: box.height_cm.toString(),
1039
- max_weight_kg: box.max_weight_kg.toString(),
1040
- price_thb: box.price_thb.toString(),
1041
- active: box.active
1079
+ kind: area.kind,
1080
+ value: area.value,
1081
+ active: area.active
1042
1082
  });
1043
1083
  }
1044
- }, [box]);
1084
+ }, [area]);
1045
1085
  const handleSubmit = async (e) => {
1046
1086
  e.preventDefault();
1047
1087
  const errors = [];
1048
- if (!formData.name.trim()) {
1049
- errors.push("กรุณากรอกชื่อกล่อง");
1050
- }
1051
- const width = parseFloat(formData.width_cm);
1052
- const length = parseFloat(formData.length_cm);
1053
- const height = parseFloat(formData.height_cm);
1054
- const maxWeight = parseFloat(formData.max_weight_kg);
1055
- const price = parseFloat(formData.price_thb);
1056
- if (isNaN(width) || width <= 0) {
1057
- errors.push("ความกว้างต้องเป็นตัวเลขมากกว่า 0");
1058
- }
1059
- if (isNaN(length) || length <= 0) {
1060
- errors.push("ความยาวต้องเป็นตัวเลขมากกว่า 0");
1061
- }
1062
- if (isNaN(height) || height <= 0) {
1063
- errors.push("ความสูงต้องเป็นตัวเลขมากกว่า 0");
1064
- }
1065
- if (isNaN(maxWeight) || maxWeight <= 0) {
1066
- errors.push("น้ำหนักสูงสุดต้องเป็นตัวเลขมากกว่า 0");
1088
+ const trimmedValue = formData.value.trim();
1089
+ if (!trimmedValue) {
1090
+ errors.push("กรุณากรอกค่า");
1067
1091
  }
1068
- if (isNaN(price) || price < 0) {
1069
- errors.push("ราคาต้องเป็นตัวเลขไม่ติดลบ");
1092
+ if (formData.kind === "PROVINCE") {
1093
+ if (!TH_PROVINCES.includes(trimmedValue)) {
1094
+ errors.push("จังหวัดไม่ถูกต้อง กรุณาตรวจสอบการสะกดชื่อจังหวัด");
1095
+ }
1096
+ } else if (formData.kind === "POSTCODE_PREFIX") {
1097
+ if (!/^\d{1,5}$/.test(trimmedValue)) {
1098
+ errors.push("รหัสไปรษณีย์ต้องเป็นตัวเลข 1-5 หลัก");
1099
+ }
1070
1100
  }
1071
1101
  if (errors.length > 0) {
1072
1102
  toast.error("ข้อมูลไม่ถูกต้อง", {
@@ -1077,16 +1107,12 @@ const ParcelBoxModal = ({ box, onClose }) => {
1077
1107
  setIsSaving(true);
1078
1108
  try {
1079
1109
  const payload = {
1080
- name: formData.name.trim(),
1081
- width_cm: width,
1082
- length_cm: length,
1083
- height_cm: height,
1084
- max_weight_kg: maxWeight,
1085
- price_thb: price,
1110
+ kind: formData.kind,
1111
+ value: trimmedValue,
1086
1112
  active: formData.active
1087
1113
  };
1088
- const url = box ? `/admin/boxes/${box.id}` : "/admin/boxes";
1089
- const method = box ? "PUT" : "POST";
1114
+ const url = area ? `/admin/service-areas/${area.id}` : "/admin/service-areas";
1115
+ const method = area ? "PUT" : "POST";
1090
1116
  const response = await fetch(url, {
1091
1117
  method,
1092
1118
  headers: { "Content-Type": "application/json" },
@@ -1095,7 +1121,7 @@ const ParcelBoxModal = ({ box, onClose }) => {
1095
1121
  });
1096
1122
  if (response.ok) {
1097
1123
  toast.success("สำเร็จ", {
1098
- description: box ? "แก้ไขกล่องพัสดุแล้ว" : "สร้างกล่องพัสดุใหม่แล้ว"
1124
+ description: area ? "แก้ไขพื้นที่บริการแล้ว" : "สร้างพื้นที่บริการใหม่แล้ว"
1099
1125
  });
1100
1126
  onClose();
1101
1127
  } else {
@@ -1111,97 +1137,53 @@ const ParcelBoxModal = ({ box, onClose }) => {
1111
1137
  }
1112
1138
  };
1113
1139
  return /* @__PURE__ */ jsx(Drawer, { open: true, onOpenChange: (open) => !open && onClose(), children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
1114
- /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: box ? "แก้ไขกล่องพัสดุ" : "สร้างกล่องพัสดุใหม่" }) }),
1140
+ /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { children: area ? "แก้ไขพื้นที่บริการ" : "สร้างพื้นที่บริการใหม่" }) }),
1115
1141
  /* @__PURE__ */ jsx(Drawer.Body, { children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-y-4", children: [
1116
1142
  /* @__PURE__ */ jsxs("div", { children: [
1117
- /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "ชื่อกล่อง *" }),
1118
- /* @__PURE__ */ jsx(
1119
- Input,
1120
- {
1121
- id: "name",
1122
- value: formData.name,
1123
- onChange: (e) => setFormData({ ...formData, name: e.target.value }),
1124
- placeholder: "เช่น กล่อง S, กล่อง M",
1125
- required: true
1126
- }
1127
- )
1128
- ] }),
1129
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-3 gap-x-4", children: [
1130
- /* @__PURE__ */ jsxs("div", { children: [
1131
- /* @__PURE__ */ jsx(Label, { htmlFor: "width", children: "ความกว้าง (cm) *" }),
1132
- /* @__PURE__ */ jsx(
1133
- Input,
1134
- {
1135
- id: "width",
1136
- type: "number",
1137
- step: "0.1",
1138
- value: formData.width_cm,
1139
- onChange: (e) => setFormData({ ...formData, width_cm: e.target.value }),
1140
- placeholder: "20",
1141
- required: true
1142
- }
1143
- )
1144
- ] }),
1145
- /* @__PURE__ */ jsxs("div", { children: [
1146
- /* @__PURE__ */ jsx(Label, { htmlFor: "length", children: "ความยาว (cm) *" }),
1147
- /* @__PURE__ */ jsx(
1148
- Input,
1149
- {
1150
- id: "length",
1151
- type: "number",
1152
- step: "0.1",
1153
- value: formData.length_cm,
1154
- onChange: (e) => setFormData({ ...formData, length_cm: e.target.value }),
1155
- placeholder: "30",
1156
- required: true
1157
- }
1158
- )
1159
- ] }),
1160
- /* @__PURE__ */ jsxs("div", { children: [
1161
- /* @__PURE__ */ jsx(Label, { htmlFor: "height", children: "ความสูง (cm) *" }),
1162
- /* @__PURE__ */ jsx(
1163
- Input,
1164
- {
1165
- id: "height",
1166
- type: "number",
1167
- step: "0.1",
1168
- value: formData.height_cm,
1169
- onChange: (e) => setFormData({ ...formData, height_cm: e.target.value }),
1170
- placeholder: "15",
1171
- required: true
1172
- }
1173
- )
1174
- ] })
1175
- ] }),
1176
- /* @__PURE__ */ jsxs("div", { children: [
1177
- /* @__PURE__ */ jsx(Label, { htmlFor: "maxWeight", children: "น้ำหนักสูงสุด (kg) *" }),
1178
- /* @__PURE__ */ jsx(
1179
- Input,
1143
+ /* @__PURE__ */ jsx(Label, { htmlFor: "kind", children: "ประเภท *" }),
1144
+ /* @__PURE__ */ jsxs(
1145
+ Select,
1180
1146
  {
1181
- id: "maxWeight",
1182
- type: "number",
1183
- step: "0.1",
1184
- value: formData.max_weight_kg,
1185
- onChange: (e) => setFormData({ ...formData, max_weight_kg: e.target.value }),
1186
- placeholder: "0.5",
1187
- required: true
1147
+ value: formData.kind,
1148
+ onValueChange: (value) => setFormData({ ...formData, kind: value, value: "" }),
1149
+ required: true,
1150
+ children: [
1151
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "เลือกประเภท" }) }),
1152
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1153
+ /* @__PURE__ */ jsx(Select.Item, { value: "PROVINCE", children: "จังหวัด" }),
1154
+ /* @__PURE__ */ jsx(Select.Item, { value: "POSTCODE_PREFIX", children: "รหัสไปรษณีย์" })
1155
+ ] })
1156
+ ]
1188
1157
  }
1189
1158
  )
1190
1159
  ] }),
1191
1160
  /* @__PURE__ */ jsxs("div", { children: [
1192
- /* @__PURE__ */ jsx(Label, { htmlFor: "price", children: "ราคา (THB) *" }),
1193
- /* @__PURE__ */ jsx(
1161
+ /* @__PURE__ */ jsx(Label, { htmlFor: "value", children: formData.kind === "PROVINCE" ? "ชื่อจังหวัด *" : "รหัสไปรษณีย์ (1-5 หลัก) *" }),
1162
+ formData.kind === "PROVINCE" ? /* @__PURE__ */ jsxs(
1163
+ Select,
1164
+ {
1165
+ value: formData.value,
1166
+ onValueChange: (value) => setFormData({ ...formData, value }),
1167
+ required: true,
1168
+ children: [
1169
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "เลือกจังหวัด" }) }),
1170
+ /* @__PURE__ */ jsx(Select.Content, { children: TH_PROVINCES.map((province) => /* @__PURE__ */ jsx(Select.Item, { value: province, children: province }, province)) })
1171
+ ]
1172
+ }
1173
+ ) : /* @__PURE__ */ jsx(
1194
1174
  Input,
1195
1175
  {
1196
- id: "price",
1197
- type: "number",
1198
- step: "0.01",
1199
- value: formData.price_thb,
1200
- onChange: (e) => setFormData({ ...formData, price_thb: e.target.value }),
1201
- placeholder: "10.00",
1176
+ id: "value",
1177
+ type: "text",
1178
+ value: formData.value,
1179
+ onChange: (e) => setFormData({ ...formData, value: e.target.value }),
1180
+ placeholder: "เช่น 10, 102, 10200",
1181
+ maxLength: 5,
1182
+ pattern: "\\d{1,5}",
1202
1183
  required: true
1203
1184
  }
1204
- )
1185
+ ),
1186
+ formData.kind === "POSTCODE_PREFIX" && /* @__PURE__ */ jsx("p", { className: "text-xs text-ui-fg-subtle mt-1", children: 'ใส่รหัส 1-5 หลักเพื่อครอบคลุมหลายพื้นที่ เช่น "10" = กรุงเทพฯ ทั้งหมด' })
1205
1187
  ] }),
1206
1188
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
1207
1189
  /* @__PURE__ */ jsx(
@@ -1215,59 +1197,81 @@ const ParcelBoxModal = ({ box, onClose }) => {
1215
1197
  /* @__PURE__ */ jsx(Label, { htmlFor: "active", children: "เปิดใช้งาน" })
1216
1198
  ] }),
1217
1199
  /* @__PURE__ */ jsxs(Drawer.Footer, { children: [
1218
- /* @__PURE__ */ jsx(Button, { type: "button", variant: "secondary", onClick: onClose, disabled: isSaving, children: "ยกเลิก" }),
1200
+ /* @__PURE__ */ jsx(
1201
+ Button,
1202
+ {
1203
+ type: "button",
1204
+ variant: "secondary",
1205
+ onClick: onClose,
1206
+ disabled: isSaving,
1207
+ children: "ยกเลิก"
1208
+ }
1209
+ ),
1219
1210
  /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isSaving, children: isSaving ? "กำลังบันทึก..." : "บันทึก" })
1220
1211
  ] })
1221
1212
  ] }) })
1222
1213
  ] }) });
1223
1214
  };
1224
- const ParcelBoxesTable = () => {
1225
- const [boxes, setBoxes] = useState([]);
1226
- const [filteredBoxes, setFilteredBoxes] = useState([]);
1215
+ const AREA_KINDS = [
1216
+ { value: "ALL", label: "ทั้งหมด" },
1217
+ { value: "PROVINCE", label: "จังหวัด" },
1218
+ { value: "POSTCODE_PREFIX", label: "รหัสไปรษณีย์" }
1219
+ ];
1220
+ const ServiceAreasTable = () => {
1221
+ const [areas, setAreas] = useState([]);
1222
+ const [filteredAreas, setFilteredAreas] = useState([]);
1227
1223
  const [searchTerm, setSearchTerm] = useState("");
1224
+ const [kindFilter, setKindFilter] = useState("ALL");
1228
1225
  const [isModalOpen, setIsModalOpen] = useState(false);
1229
- const [editingBox, setEditingBox] = useState(null);
1226
+ const [editingArea, setEditingArea] = useState(null);
1230
1227
  const [isLoading, setIsLoading] = useState(false);
1231
- const [deleteBoxId, setDeleteBoxId] = useState(null);
1232
- const [deleteBoxName, setDeleteBoxName] = useState("");
1228
+ const [deleteAreaId, setDeleteAreaId] = useState(null);
1229
+ const [deleteAreaValue, setDeleteAreaValue] = useState("");
1233
1230
  useEffect(() => {
1234
- fetchBoxes();
1231
+ fetchAreas();
1235
1232
  }, []);
1236
1233
  useEffect(() => {
1237
- const filtered = boxes.filter(
1238
- (box) => box.name.toLowerCase().includes(searchTerm.toLowerCase())
1239
- );
1240
- setFilteredBoxes(filtered);
1241
- }, [searchTerm, boxes]);
1242
- const fetchBoxes = async () => {
1234
+ let filtered = areas;
1235
+ if (kindFilter !== "ALL") {
1236
+ filtered = filtered.filter((area) => area.kind === kindFilter);
1237
+ }
1238
+ if (searchTerm) {
1239
+ filtered = filtered.filter(
1240
+ (area) => area.value.toLowerCase().includes(searchTerm.toLowerCase())
1241
+ );
1242
+ }
1243
+ setFilteredAreas(filtered);
1244
+ }, [searchTerm, kindFilter, areas]);
1245
+ const fetchAreas = async () => {
1243
1246
  setIsLoading(true);
1244
1247
  try {
1245
- const response = await fetch("/admin/boxes", {
1248
+ const response = await fetch("/admin/service-areas", {
1246
1249
  credentials: "include"
1247
1250
  });
1248
1251
  const data = await response.json();
1249
- setBoxes(data.boxes || []);
1252
+ console.log("Fetched service areas:", data);
1253
+ setAreas(data.service_areas || []);
1250
1254
  } catch (error) {
1251
1255
  toast.error("ข้อผิดพลาด", {
1252
- description: "ไม่สามารถโหลดข้อมูลกล่องพัสดุได้"
1256
+ description: "ไม่สามารถโหลดข้อมูลพื้นที่บริการได้"
1253
1257
  });
1254
1258
  } finally {
1255
1259
  setIsLoading(false);
1256
1260
  }
1257
1261
  };
1258
- const handleToggleActive = async (box) => {
1262
+ const handleToggleActive = async (area) => {
1259
1263
  try {
1260
- const response = await fetch(`/admin/boxes/${box.id}`, {
1264
+ const response = await fetch(`/admin/service-areas/${area.id}`, {
1261
1265
  method: "PUT",
1262
1266
  headers: { "Content-Type": "application/json" },
1263
1267
  credentials: "include",
1264
- body: JSON.stringify({ ...box, active: !box.active })
1268
+ body: JSON.stringify({ ...area, active: !area.active })
1265
1269
  });
1266
1270
  if (response.ok) {
1267
1271
  toast.success("สำเร็จ", {
1268
- description: `${box.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}กล่อง ${box.name} แล้ว`
1272
+ description: `${area.active ? "ปิดใช้งาน" : "เปิดใช้งาน"}พื้นที่ ${area.value} แล้ว`
1269
1273
  });
1270
- fetchBoxes();
1274
+ fetchAreas();
1271
1275
  } else {
1272
1276
  throw new Error("Failed to update");
1273
1277
  }
@@ -1278,91 +1282,87 @@ const ParcelBoxesTable = () => {
1278
1282
  }
1279
1283
  };
1280
1284
  const handleDelete = async () => {
1281
- if (!deleteBoxId) return;
1285
+ if (!deleteAreaId) return;
1282
1286
  try {
1283
- const response = await fetch(`/admin/boxes/${deleteBoxId}`, {
1287
+ const response = await fetch(`/admin/service-areas/${deleteAreaId}`, {
1284
1288
  method: "DELETE",
1285
1289
  credentials: "include"
1286
1290
  });
1287
1291
  if (response.ok) {
1288
1292
  toast.success("สำเร็จ", {
1289
- description: `ลบกล่อง ${deleteBoxName} แล้ว`
1293
+ description: `ลบพื้นที่ ${deleteAreaValue} แล้ว`
1290
1294
  });
1291
- fetchBoxes();
1295
+ fetchAreas();
1292
1296
  } else {
1293
1297
  throw new Error("Failed to delete");
1294
1298
  }
1295
1299
  } catch (error) {
1296
1300
  toast.error("ข้อผิดพลาด", {
1297
- description: "ไม่สามารถลบกล่องได้"
1301
+ description: "ไม่สามารถลบพื้นที่ได้"
1298
1302
  });
1299
1303
  } finally {
1300
- setDeleteBoxId(null);
1301
- setDeleteBoxName("");
1304
+ setDeleteAreaId(null);
1305
+ setDeleteAreaValue("");
1302
1306
  }
1303
1307
  };
1304
- const handleEdit = (box) => {
1305
- setEditingBox(box);
1308
+ const handleEdit = (area) => {
1309
+ setEditingArea(area);
1306
1310
  setIsModalOpen(true);
1307
1311
  };
1308
1312
  const handleCreateNew = () => {
1309
- setEditingBox(null);
1313
+ setEditingArea(null);
1310
1314
  setIsModalOpen(true);
1311
1315
  };
1312
1316
  const handleModalClose = () => {
1313
1317
  setIsModalOpen(false);
1314
- setEditingBox(null);
1315
- fetchBoxes();
1318
+ setEditingArea(null);
1319
+ fetchAreas();
1316
1320
  };
1317
- const openDeletePrompt = (id, name) => {
1318
- setDeleteBoxId(id);
1319
- setDeleteBoxName(name);
1321
+ const openDeletePrompt = (id, value) => {
1322
+ setDeleteAreaId(id);
1323
+ setDeleteAreaValue(value);
1320
1324
  };
1321
1325
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1322
1326
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
1323
1327
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-4", children: [
1324
- /* @__PURE__ */ jsx(
1325
- Input,
1326
- {
1327
- type: "search",
1328
- placeholder: "ค้นหาชื่อกล่อง...",
1329
- value: searchTerm,
1330
- onChange: (e) => setSearchTerm(e.target.value),
1331
- className: "max-w-md"
1332
- }
1333
- ),
1328
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-x-4 flex-1", children: [
1329
+ /* @__PURE__ */ jsx(
1330
+ Input,
1331
+ {
1332
+ type: "search",
1333
+ placeholder: "ค้นหาจังหวัดหรือรหัสไปรษณีย์...",
1334
+ value: searchTerm,
1335
+ onChange: (e) => setSearchTerm(e.target.value),
1336
+ className: "max-w-md"
1337
+ }
1338
+ ),
1339
+ /* @__PURE__ */ jsxs(Select, { value: kindFilter, onValueChange: setKindFilter, children: [
1340
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "ประเภท" }) }),
1341
+ /* @__PURE__ */ jsx(Select.Content, { children: AREA_KINDS.map((kind) => /* @__PURE__ */ jsx(Select.Item, { value: kind.value, children: kind.label }, kind.value)) })
1342
+ ] })
1343
+ ] }),
1334
1344
  /* @__PURE__ */ jsxs(Button, { onClick: handleCreateNew, children: [
1335
1345
  /* @__PURE__ */ jsx(Plus, {}),
1336
- "สร้างกล่องใหม่"
1346
+ "สร้างพื้นที่ใหม่"
1337
1347
  ] })
1338
1348
  ] }),
1339
1349
  /* @__PURE__ */ jsxs(Table, { children: [
1340
1350
  /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
1341
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ชื่อ" }),
1342
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ขนาด (กว้าง×ยาว×สูง cm)" }),
1343
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "น้ำหนักสูงสุด (kg)" }),
1344
- /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ราคา (THB)" }),
1351
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ประเภท" }),
1352
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "ค่า" }),
1345
1353
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "สถานะ" }),
1346
1354
  /* @__PURE__ */ jsx(Table.HeaderCell, { className: "text-right", children: "การจัดการ" })
1347
1355
  ] }) }),
1348
- /* @__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: [
1349
- /* @__PURE__ */ jsx(Table.Cell, { children: box.name }),
1350
- /* @__PURE__ */ jsxs(Table.Cell, { children: [
1351
- box.width_cm,
1352
- " × ",
1353
- box.length_cm,
1354
- " × ",
1355
- box.height_cm
1356
- ] }),
1357
- /* @__PURE__ */ jsx(Table.Cell, { children: box.max_weight_kg }),
1358
- /* @__PURE__ */ jsx(Table.Cell, { children: box.price_thb.toFixed(2) }),
1356
+ /* @__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: [
1357
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { color: area.kind === "PROVINCE" ? "blue" : "purple", children: area.kind === "PROVINCE" ? "จังหวัด" : "รหัสไปรษณีย์" }) }),
1358
+ /* @__PURE__ */ jsx(Table.Cell, { children: area.value }),
1359
1359
  /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
1360
1360
  Badge,
1361
1361
  {
1362
- color: box.active ? "green" : "grey",
1362
+ color: area.active ? "green" : "grey",
1363
1363
  className: "cursor-pointer",
1364
- onClick: () => handleToggleActive(box),
1365
- children: box.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
1364
+ onClick: () => handleToggleActive(area),
1365
+ children: area.active ? "เปิดใช้งาน" : "ปิดใช้งาน"
1366
1366
  }
1367
1367
  ) }),
1368
1368
  /* @__PURE__ */ jsx(Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [
@@ -1371,7 +1371,7 @@ const ParcelBoxesTable = () => {
1371
1371
  {
1372
1372
  variant: "transparent",
1373
1373
  size: "small",
1374
- onClick: () => handleEdit(box),
1374
+ onClick: () => handleEdit(area),
1375
1375
  children: /* @__PURE__ */ jsx(Edit, {})
1376
1376
  }
1377
1377
  ),
@@ -1380,30 +1380,30 @@ const ParcelBoxesTable = () => {
1380
1380
  {
1381
1381
  variant: "transparent",
1382
1382
  size: "small",
1383
- onClick: () => openDeletePrompt(box.id, box.name),
1383
+ onClick: () => openDeletePrompt(area.id, area.value),
1384
1384
  children: /* @__PURE__ */ jsx(Trash, {})
1385
1385
  }
1386
1386
  )
1387
1387
  ] }) })
1388
- ] }, box.id)) })
1388
+ ] }, area.id)) })
1389
1389
  ] })
1390
1390
  ] }),
1391
- isModalOpen && /* @__PURE__ */ jsx(ParcelBoxModal, { box: editingBox, onClose: handleModalClose }),
1391
+ isModalOpen && /* @__PURE__ */ jsx(ServiceAreaModal, { area: editingArea, onClose: handleModalClose }),
1392
1392
  /* @__PURE__ */ jsx(
1393
1393
  Prompt,
1394
1394
  {
1395
1395
  variant: "confirmation",
1396
- open: !!deleteBoxId,
1396
+ open: !!deleteAreaId,
1397
1397
  onOpenChange: () => {
1398
- setDeleteBoxId(null);
1399
- setDeleteBoxName("");
1398
+ setDeleteAreaId(null);
1399
+ setDeleteAreaValue("");
1400
1400
  },
1401
1401
  children: /* @__PURE__ */ jsxs(Prompt.Content, { children: [
1402
1402
  /* @__PURE__ */ jsxs(Prompt.Header, { children: [
1403
- /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบกล่องพัสดุ" }),
1403
+ /* @__PURE__ */ jsx(Prompt.Title, { children: "ลบพื้นที่บริการ" }),
1404
1404
  /* @__PURE__ */ jsxs(Prompt.Description, { children: [
1405
- 'คุณต้องการลบกล่อง "',
1406
- deleteBoxName,
1405
+ 'คุณต้องการลบพื้นที่ "',
1406
+ deleteAreaValue,
1407
1407
  '" ใช่หรือไม่? การดำเนินการนี้ไม่สามารถย้อนกลับได้'
1408
1408
  ] })
1409
1409
  ] }),
@@ -1416,15 +1416,15 @@ const ParcelBoxesTable = () => {
1416
1416
  )
1417
1417
  ] });
1418
1418
  };
1419
- const BoxesPage = () => {
1419
+ const AreasPage = () => {
1420
1420
  return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-4", children: [
1421
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "กล่องพัสดุ" }) }),
1422
- /* @__PURE__ */ jsx(ParcelBoxesTable, {})
1421
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsx(Heading, { level: "h1", children: "พื้นที่บริการ" }) }),
1422
+ /* @__PURE__ */ jsx(ServiceAreasTable, {})
1423
1423
  ] }) });
1424
1424
  };
1425
1425
  const config$2 = defineRouteConfig({
1426
- icon: ArchiveBox,
1427
- label: "กล่องพัสดุ"
1426
+ icon: MapPin,
1427
+ label: "พื้นที่บริการ"
1428
1428
  });
1429
1429
  const CATEGORIES$1 = [
1430
1430
  { value: "PACKAGING", label: "วัสดุหีบห่อ" },
@@ -2377,10 +2377,6 @@ const widgetModule = { widgets: [
2377
2377
  ] };
2378
2378
  const routeModule = {
2379
2379
  routes: [
2380
- {
2381
- Component: AreasPage,
2382
- path: "/areas"
2383
- },
2384
2380
  {
2385
2381
  Component: BasePricingPage,
2386
2382
  path: "/base-pricing"
@@ -2389,6 +2385,10 @@ const routeModule = {
2389
2385
  Component: BoxesPage,
2390
2386
  path: "/boxes"
2391
2387
  },
2388
+ {
2389
+ Component: AreasPage,
2390
+ path: "/areas"
2391
+ },
2392
2392
  {
2393
2393
  Component: MaterialCostsPage,
2394
2394
  path: "/material-costs"
@@ -2401,15 +2401,21 @@ const routeModule = {
2401
2401
  };
2402
2402
  const menuItemModule = {
2403
2403
  menuItems: [
2404
+ {
2405
+ label: config$2.label,
2406
+ icon: config$2.icon,
2407
+ path: "/areas",
2408
+ nested: void 0
2409
+ },
2404
2410
  {
2405
2411
  label: config$4.label,
2406
2412
  icon: config$4.icon,
2407
- path: "/areas",
2413
+ path: "/base-pricing",
2408
2414
  nested: void 0
2409
2415
  },
2410
2416
  {
2411
- label: config$2.label,
2412
- icon: config$2.icon,
2417
+ label: config$3.label,
2418
+ icon: config$3.icon,
2413
2419
  path: "/boxes",
2414
2420
  nested: void 0
2415
2421
  },
@@ -2424,12 +2430,6 @@ const menuItemModule = {
2424
2430
  icon: config.icon,
2425
2431
  path: "/rates",
2426
2432
  nested: void 0
2427
- },
2428
- {
2429
- label: config$3.label,
2430
- icon: config$3.icon,
2431
- path: "/base-pricing",
2432
- nested: void 0
2433
2433
  }
2434
2434
  ]
2435
2435
  };