@infuro/cms-core 1.0.66 → 1.0.68

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.
Files changed (57) hide show
  1. package/dist/admin.cjs +214 -32
  2. package/dist/admin.js +214 -32
  3. package/dist/api.cjs +45 -42
  4. package/dist/api.js +12 -9
  5. package/dist/auth.cjs +51 -51
  6. package/dist/auth.js +3 -3
  7. package/dist/{chunk-QYRXLURF.cjs → chunk-22XKONB5.cjs} +640 -145
  8. package/dist/{chunk-MVHDC3XF.js → chunk-5NOZSG6J.js} +22 -11
  9. package/dist/{chunk-TU23GJPJ.js → chunk-7JCCPQEF.js} +1 -1
  10. package/dist/{chunk-WMMZZRDJ.cjs → chunk-GN4LKG4V.cjs} +1 -1
  11. package/dist/{chunk-KM2I6AFP.cjs → chunk-HBUV73RB.cjs} +9 -9
  12. package/dist/chunk-IKTBZJHT.js +16 -0
  13. package/dist/chunk-M5GPOPGX.cjs +49 -0
  14. package/dist/{chunk-T33KU5G5.js → chunk-MYUGQHU4.js} +548 -53
  15. package/dist/{chunk-NV5IRHI3.js → chunk-N4LBZXBG.js} +2 -2
  16. package/dist/{chunk-J7FMZK66.cjs → chunk-O4AFPDQ4.cjs} +22 -11
  17. package/dist/{chunk-4U6DATGZ.cjs → chunk-OV5TRZET.cjs} +7 -7
  18. package/dist/chunk-P6S4XFZO.cjs +18 -0
  19. package/dist/{chunk-RCE5SJBA.js → chunk-SKJH7PX4.js} +1 -1
  20. package/dist/{chunk-5MZFQRDW.cjs → chunk-SMHQV3WL.cjs} +4 -4
  21. package/dist/chunk-SUUD7OUG.cjs +455 -0
  22. package/dist/{chunk-XFDIIVZB.cjs → chunk-UMC7W5G3.cjs} +3 -3
  23. package/dist/chunk-WKDBMDUX.js +45 -0
  24. package/dist/{chunk-6DBDJ4VD.js → chunk-Z5G54EGD.js} +2 -2
  25. package/dist/chunk-Z5OB5QGN.js +465 -0
  26. package/dist/chunk-ZIT4IP6N.js +445 -0
  27. package/dist/chunk-ZX5U3VCB.cjs +471 -0
  28. package/dist/{chunk-NR44CK5E.js → chunk-ZY64VJMS.js} +1 -1
  29. package/dist/email-queue-3QBQ63F7.js +8 -0
  30. package/dist/{email-queue-4OY45JIU.cjs → email-queue-K4E4OFI7.cjs} +9 -6
  31. package/dist/{emit-order-notification-trigger-ZD5YN3JM.cjs → emit-order-notification-trigger-ROASTYQP.cjs} +3 -3
  32. package/dist/{emit-order-notification-trigger-EJJZ6XTS.js → emit-order-notification-trigger-YUQTPELC.js} +1 -1
  33. package/dist/{erp-order-invoice-YUSPZ7CE.cjs → erp-order-invoice-AZ5MX2JB.cjs} +8 -5
  34. package/dist/{erp-order-invoice-H6HCJ7YS.js → erp-order-invoice-XSYHAMBS.js} +4 -1
  35. package/dist/generate-local-invoice-pdf-BQTCL5MW.cjs +12 -0
  36. package/dist/generate-local-invoice-pdf-OCFG47SE.js +3 -0
  37. package/dist/index.cjs +337 -330
  38. package/dist/index.d.cts +21 -2
  39. package/dist/index.d.ts +21 -2
  40. package/dist/index.js +18 -15
  41. package/dist/invoice-templates-GZ33OENC.js +2 -0
  42. package/dist/invoice-templates-RB462AQN.cjs +19 -0
  43. package/dist/migrations/1783300000000-CreateOrderAssigneesTable.ts +43 -0
  44. package/dist/{order-assignees-handlers-NPKD64P6.cjs → order-assignees-handlers-KF7RMTV5.cjs} +77 -8
  45. package/dist/{order-assignees-handlers-LKMAGLG6.js → order-assignees-handlers-L3RVKUBS.js} +77 -8
  46. package/dist/{order-completion-otp-handlers-NK65LOLV.cjs → order-completion-otp-handlers-DDQREULW.cjs} +75 -18
  47. package/dist/{order-completion-otp-handlers-LFRHXWK4.js → order-completion-otp-handlers-NROWBGXN.js} +73 -16
  48. package/dist/{order-notification-dispatcher-LL7ETKLU.cjs → order-notification-dispatcher-6HCJ6Q75.cjs} +12 -9
  49. package/dist/{order-notification-dispatcher-ECPFI7CD.js → order-notification-dispatcher-KM2SY7TX.js} +7 -4
  50. package/dist/{rbac-debug-db-5R6XFPSV.js → rbac-debug-db-DFZWZ6GV.js} +1 -1
  51. package/dist/{rbac-debug-db-JKK2MCWF.cjs → rbac-debug-db-KWV7D5PQ.cjs} +2 -2
  52. package/dist/resolve-invoice-asset-url-JEZRENJW.cjs +11 -0
  53. package/dist/resolve-invoice-asset-url-QZ2FRDHI.js +2 -0
  54. package/package.json +1 -1
  55. package/dist/chunk-GLD263KW.cjs +0 -862
  56. package/dist/chunk-OPJEV44S.js +0 -847
  57. package/dist/email-queue-HGXB2FIS.js +0 -5
package/dist/admin.js CHANGED
@@ -861,7 +861,7 @@ var init_admin_config_context = __esm({
861
861
  var CMS_VERSION;
862
862
  var init_cms_version = __esm({
863
863
  "src/lib/cms-version.ts"() {
864
- CMS_VERSION = "1.0.66" ;
864
+ CMS_VERSION = "1.0.68" ;
865
865
  }
866
866
  });
867
867
  function useCatalogCategories(enabled = true) {
@@ -13622,6 +13622,39 @@ __export(SettingsPage_exports, {
13622
13622
  default: () => SettingsPage
13623
13623
  });
13624
13624
  function InvoiceTemplatePreview({ id }) {
13625
+ if (id === "service_detailed") {
13626
+ return /* @__PURE__ */ React.createElement("div", {
13627
+ className: "h-28 rounded-md border border-sky-200 bg-white overflow-hidden shadow-sm p-1.5 space-y-1"
13628
+ }, /* @__PURE__ */ React.createElement("div", {
13629
+ className: "h-4 bg-sky-50 rounded px-1 flex items-center justify-between border border-sky-100"
13630
+ }, /* @__PURE__ */ React.createElement("div", {
13631
+ className: "h-1.5 w-10 bg-sky-700 rounded"
13632
+ }), /* @__PURE__ */ React.createElement("div", {
13633
+ className: "h-1 w-6 bg-slate-400 rounded"
13634
+ })), /* @__PURE__ */ React.createElement("div", {
13635
+ className: "rounded bg-sky-50/70 border border-sky-100 p-1 space-y-0.5"
13636
+ }, /* @__PURE__ */ React.createElement("div", {
13637
+ className: "grid grid-cols-2 gap-1"
13638
+ }, /* @__PURE__ */ React.createElement("div", {
13639
+ className: "h-1 w-full bg-sky-600/70 rounded"
13640
+ }), /* @__PURE__ */ React.createElement("div", {
13641
+ className: "h-1 w-full bg-sky-600/70 rounded"
13642
+ })), /* @__PURE__ */ React.createElement("div", {
13643
+ className: "grid grid-cols-2 gap-1"
13644
+ }, /* @__PURE__ */ React.createElement("div", {
13645
+ className: "h-1 w-full bg-slate-400 rounded"
13646
+ }), /* @__PURE__ */ React.createElement("div", {
13647
+ className: "h-1 w-full bg-slate-400 rounded"
13648
+ }))), /* @__PURE__ */ React.createElement("div", {
13649
+ className: "h-1 w-full bg-slate-100 rounded"
13650
+ }), /* @__PURE__ */ React.createElement("div", {
13651
+ className: "h-1 w-full bg-slate-100 rounded"
13652
+ }), /* @__PURE__ */ React.createElement("div", {
13653
+ className: "flex justify-end pt-0.5"
13654
+ }, /* @__PURE__ */ React.createElement("div", {
13655
+ className: "h-1.5 w-12 bg-sky-700 rounded"
13656
+ })));
13657
+ }
13625
13658
  if (id === "modern") {
13626
13659
  return /* @__PURE__ */ React.createElement("div", {
13627
13660
  className: "h-28 rounded-md border border-slate-200 bg-white overflow-hidden shadow-sm"
@@ -13800,6 +13833,7 @@ function SettingsPage() {
13800
13833
  const [storeSettingsLoading, setStoreSettingsLoading] = useState(true);
13801
13834
  const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
13802
13835
  const [invoiceTemplate, setInvoiceTemplate] = useState("classic");
13836
+ const [invoiceIncludeQr, setInvoiceIncludeQr] = useState(false);
13803
13837
  const [companyLogo, setCompanyLogo] = useState("");
13804
13838
  const [companyName, setCompanyName] = useState("");
13805
13839
  const [companyEmail, setCompanyEmail] = useState("");
@@ -13877,6 +13911,7 @@ function SettingsPage() {
13877
13911
  setStoreEnabled(data.enabled === "true");
13878
13912
  setCurrency(data.currency || DEFAULT_CURRENCY);
13879
13913
  setInvoiceTemplate(data.invoiceTemplate || "classic");
13914
+ setInvoiceIncludeQr(data.invoice_include_qr === "true" || data.invoiceIncludeQr === "true");
13880
13915
  const logo = data.invoiceLogoUrl || data.companyLogo || data.logo || "";
13881
13916
  setCompanyLogo((prev) => logo || prev);
13882
13917
  setCompanyName(data.companyName || data.invoiceCompanyName || data.name || "");
@@ -14042,6 +14077,10 @@ function SettingsPage() {
14042
14077
  value: invoiceTemplate || "classic",
14043
14078
  type: "public"
14044
14079
  },
14080
+ invoice_include_qr: {
14081
+ value: invoiceIncludeQr ? "true" : "false",
14082
+ type: "public"
14083
+ },
14045
14084
  invoiceLogoUrl: {
14046
14085
  value: companyLogo,
14047
14086
  type: "public"
@@ -14510,24 +14549,43 @@ function SettingsPage() {
14510
14549
  placeholder: "e.g. 123 Business Rd, Suite 100\nNew York, NY 10001",
14511
14550
  rows: 3,
14512
14551
  className: "text-sm bg-white"
14513
- })))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
14514
- className: "block text-sm font-semibold text-gray-700 mb-1"
14515
- }, "Invoice PDF template"), /* @__PURE__ */ React.createElement("p", {
14552
+ })))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
14553
+ className: "flex items-center justify-between mb-1"
14554
+ }, /* @__PURE__ */ React.createElement("label", {
14555
+ className: "block text-sm font-semibold text-gray-700"
14556
+ }, "Invoice PDF template"), /* @__PURE__ */ React.createElement("label", {
14557
+ className: "inline-flex items-center gap-2 cursor-pointer select-none text-sm font-semibold text-gray-800 hover:text-gray-950"
14558
+ }, /* @__PURE__ */ React.createElement("input", {
14559
+ type: "checkbox",
14560
+ checked: invoiceIncludeQr,
14561
+ onChange: /* @__PURE__ */ __name((e) => setInvoiceIncludeQr(e.target.checked), "onChange"),
14562
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 accent-blue-600 cursor-pointer"
14563
+ }), /* @__PURE__ */ React.createElement("span", null, "Add QR"))), /* @__PURE__ */ React.createElement("p", {
14516
14564
  className: "text-xs text-gray-500 mb-3"
14517
14565
  }, "Used when generating invoices in the app (and as fallback when ERP invoice is unavailable). Company logo, name, email, phone, and address set above are shown in the invoice header."), /* @__PURE__ */ React.createElement("div", {
14518
14566
  className: "grid gap-3 sm:grid-cols-2"
14519
14567
  }, INVOICE_TEMPLATE_CARDS.map((opt) => {
14520
14568
  const selected = invoiceTemplate === opt.id;
14521
- return /* @__PURE__ */ React.createElement("button", {
14569
+ return /* @__PURE__ */ React.createElement("div", {
14522
14570
  key: opt.id,
14523
- type: "button",
14524
14571
  onClick: /* @__PURE__ */ __name(() => setInvoiceTemplate(opt.id), "onClick"),
14525
- className: `text-left rounded-lg border p-3 transition ${selected ? "border-blue-500 bg-blue-50 ring-1 ring-blue-500" : "border-gray-200 bg-white hover:border-gray-300"}`
14572
+ className: `text-left rounded-lg border p-3 transition cursor-pointer ${selected ? "border-blue-500 bg-blue-50/70 ring-1 ring-blue-500" : "border-gray-200 bg-white hover:border-gray-300"}`
14526
14573
  }, /* @__PURE__ */ React.createElement(InvoiceTemplatePreview, {
14527
14574
  id: opt.id
14528
14575
  }), /* @__PURE__ */ React.createElement("div", {
14529
- className: "text-sm font-semibold text-gray-800 mt-2"
14530
- }, opt.label), /* @__PURE__ */ React.createElement("div", {
14576
+ className: "flex items-center justify-between mt-2"
14577
+ }, /* @__PURE__ */ React.createElement("div", {
14578
+ className: "text-sm font-semibold text-gray-800"
14579
+ }, opt.label), /* @__PURE__ */ React.createElement("button", {
14580
+ type: "button",
14581
+ onClick: /* @__PURE__ */ __name((e) => {
14582
+ e.stopPropagation();
14583
+ window.open(`/api/settings/invoice-preview?template=${encodeURIComponent(opt.id)}&qr=${invoiceIncludeQr ? "1" : "0"}`, "_blank");
14584
+ }, "onClick"),
14585
+ className: "text-[11px] font-medium text-blue-600 hover:text-blue-800 hover:underline inline-flex items-center gap-1 py-0.5 px-1.5 rounded bg-blue-50 hover:bg-blue-100/80 transition"
14586
+ }, /* @__PURE__ */ React.createElement(Eye, {
14587
+ className: "w-3 h-3"
14588
+ }), "Preview")), /* @__PURE__ */ React.createElement("div", {
14531
14589
  className: "text-xs text-gray-500 mt-0.5"
14532
14590
  }, opt.description));
14533
14591
  }))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
@@ -14756,6 +14814,11 @@ var init_SettingsPage = __esm({
14756
14814
  id: "bold",
14757
14815
  label: "Bold",
14758
14816
  description: "Strong header band and clear payment summary."
14817
+ },
14818
+ {
14819
+ id: "service_detailed",
14820
+ label: "Service Detailed",
14821
+ description: "Includes order date, service date, slot, and assigned technician."
14759
14822
  }
14760
14823
  ];
14761
14824
  __name(InvoiceTemplatePreview, "InvoiceTemplatePreview");
@@ -23245,6 +23308,7 @@ function VendorTeamPage() {
23245
23308
  const [inviteDialog, setInviteDialog] = useState(null);
23246
23309
  const [sendingInviteEmail, setSendingInviteEmail] = useState(false);
23247
23310
  const [linkCopied, setLinkCopied] = useState(false);
23311
+ const [resendingUserId, setResendingUserId] = useState(null);
23248
23312
  const assignableRoles = roles.filter((r) => !r.isOwnerRole);
23249
23313
  const load = useCallback(async () => {
23250
23314
  setLoading(true);
@@ -23323,6 +23387,31 @@ function VendorTeamPage() {
23323
23387
  setInviteDialog(null);
23324
23388
  setLinkCopied(false);
23325
23389
  }, "closeInviteDialog");
23390
+ const handleResendInvite = /* @__PURE__ */ __name(async (userId) => {
23391
+ setResendingUserId(userId);
23392
+ try {
23393
+ const res = await fetch("/api/admin/vendor/team/send-invite", {
23394
+ method: "POST",
23395
+ headers: {
23396
+ "Content-Type": "application/json"
23397
+ },
23398
+ body: JSON.stringify({
23399
+ userId
23400
+ })
23401
+ });
23402
+ const data = await res.json();
23403
+ if (!res.ok) {
23404
+ toast.error(data.error || data.message || "Failed to resend invite");
23405
+ return;
23406
+ }
23407
+ toast.success(data.message || "Invite email sent");
23408
+ await load();
23409
+ } catch {
23410
+ toast.error("Failed to resend invite");
23411
+ } finally {
23412
+ setResendingUserId(null);
23413
+ }
23414
+ }, "handleResendInvite");
23326
23415
  if (!canManage) {
23327
23416
  return /* @__PURE__ */ React27__default.createElement("div", {
23328
23417
  className: "min-w-0 rounded-lg bg-white shadow-md"
@@ -23494,12 +23583,26 @@ function VendorTeamPage() {
23494
23583
  value: r.id
23495
23584
  }, r.name)))), /* @__PURE__ */ React27__default.createElement("td", {
23496
23585
  className: "px-3 py-2 text-right"
23497
- }, !m.isOwnerRole && /* @__PURE__ */ React27__default.createElement(Button, {
23586
+ }, /* @__PURE__ */ React27__default.createElement("div", {
23587
+ className: "flex items-center justify-end gap-1.5"
23588
+ }, !m.isOwnerRole && String(m.inviteStatus ?? "") === "pending" && /* @__PURE__ */ React27__default.createElement(Button, {
23589
+ type: "button",
23590
+ variant: "outline",
23591
+ size: "icon",
23592
+ className: "h-7 w-7",
23593
+ disabled: resendingUserId === m.userId,
23594
+ onClick: /* @__PURE__ */ __name(() => void handleResendInvite(m.userId), "onClick"),
23595
+ title: "Resend invite"
23596
+ }, /* @__PURE__ */ React27__default.createElement(RefreshCw, {
23597
+ className: `h-3.5 w-3.5 ${resendingUserId === m.userId ? "animate-spin text-blue-600" : ""}`
23598
+ }), /* @__PURE__ */ React27__default.createElement("span", {
23599
+ className: "sr-only"
23600
+ }, "Resend invite")), !m.isOwnerRole && /* @__PURE__ */ React27__default.createElement(Button, {
23498
23601
  type: "button",
23499
23602
  variant: "ghost",
23500
23603
  size: "sm",
23501
23604
  onClick: /* @__PURE__ */ __name(() => handleRemove(m.userId), "onClick")
23502
- }, "Remove"))))))), /* @__PURE__ */ React27__default.createElement("form", {
23605
+ }, "Remove")))))))), /* @__PURE__ */ React27__default.createElement("form", {
23503
23606
  onSubmit: handleAdd,
23504
23607
  className: "space-y-4 rounded-lg border border-gray-200 p-4"
23505
23608
  }, /* @__PURE__ */ React27__default.createElement("h2", {
@@ -24564,7 +24667,10 @@ function OrderDetailPage({ orderId }) {
24564
24667
  const [cancelModal, setCancelModal] = useState(null);
24565
24668
  const [assignModalOpen, setAssignModalOpen] = useState(false);
24566
24669
  const [assigneesList, setAssigneesList] = useState([]);
24670
+ const [vendorsList, setVendorsList] = useState([]);
24671
+ const [isPlatformAdmin, setIsPlatformAdmin] = useState(false);
24567
24672
  const [loadingAssignees, setLoadingAssignees] = useState(false);
24673
+ const [selectedVendorId, setSelectedVendorId] = useState(null);
24568
24674
  const [selectedAssigneeId, setSelectedAssigneeId] = useState(null);
24569
24675
  const [savingAssignee, setSavingAssignee] = useState(false);
24570
24676
  const [completeModalOpen, setCompleteModalOpen] = useState(false);
@@ -24664,8 +24770,9 @@ function OrderDetailPage({ orderId }) {
24664
24770
  async function handleStartProcessing() {
24665
24771
  if (!order || startingProcessing) return;
24666
24772
  const currentAssigneeId = order.assignedUserId ?? order.assignedUser?.id ?? null;
24667
- if (!currentAssigneeId) {
24668
- toast.info("Please assign a teammate before starting order processing.");
24773
+ const currentVendorId = order.vendorId ?? order.vendor?.id ?? null;
24774
+ if (!currentAssigneeId && !currentVendorId) {
24775
+ toast.info("Please assign a vendor or teammate before starting order processing.");
24669
24776
  handleOpenAssignModal();
24670
24777
  return;
24671
24778
  }
@@ -24678,7 +24785,9 @@ function OrderDetailPage({ orderId }) {
24678
24785
  },
24679
24786
  body: JSON.stringify({
24680
24787
  status: "processing",
24681
- assignedUserId: currentAssigneeId
24788
+ ...currentAssigneeId ? {
24789
+ assignedUserId: currentAssigneeId
24790
+ } : {}
24682
24791
  })
24683
24792
  });
24684
24793
  const data = await res.json().catch(() => ({}));
@@ -24700,14 +24809,19 @@ function OrderDetailPage({ orderId }) {
24700
24809
  setAssignModalOpen(true);
24701
24810
  setLoadingAssignees(true);
24702
24811
  setSelectedAssigneeId(order?.assignedUserId ?? null);
24812
+ setSelectedVendorId(order?.vendorId ?? null);
24703
24813
  try {
24704
24814
  const res = await fetch(`/api/orders/${orderId}/eligible-assignees`);
24705
24815
  if (res.ok) {
24706
24816
  const data = await res.json();
24707
24817
  setAssigneesList(data.assignees ?? []);
24818
+ setVendorsList(data.vendors ?? []);
24819
+ setIsPlatformAdmin(Boolean(data.isPlatformAdmin));
24820
+ if (data.currentVendorId != null) setSelectedVendorId(data.currentVendorId);
24821
+ if (data.currentAssignedUserId != null) setSelectedAssigneeId(data.currentAssignedUserId);
24708
24822
  }
24709
24823
  } catch {
24710
- toast.error("Failed to load eligible team members");
24824
+ toast.error("Failed to load eligible assignees");
24711
24825
  } finally {
24712
24826
  setLoadingAssignees(false);
24713
24827
  }
@@ -24720,6 +24834,14 @@ function OrderDetailPage({ orderId }) {
24720
24834
  const bodyPayload = {
24721
24835
  assignedUserId: selectedAssigneeId
24722
24836
  };
24837
+ if (isPlatformAdmin) {
24838
+ const chosenAssignee = assigneesList.find((a) => a.id === selectedAssigneeId);
24839
+ if (chosenAssignee && chosenAssignee.vendorId === null) {
24840
+ bodyPayload.vendorId = 1;
24841
+ } else {
24842
+ bodyPayload.vendorId = chosenAssignee?.vendorId ?? (selectedVendorId || 1);
24843
+ }
24844
+ }
24723
24845
  const res = await fetch(`/api/orders/${orderId}`, {
24724
24846
  method: "PUT",
24725
24847
  headers: {
@@ -24729,15 +24851,15 @@ function OrderDetailPage({ orderId }) {
24729
24851
  });
24730
24852
  if (!res.ok) {
24731
24853
  const err = await res.json().catch(() => ({}));
24732
- toast.error(err.error ?? "Failed to update assignee");
24854
+ toast.error(err.error ?? "Failed to update assignment");
24733
24855
  return;
24734
24856
  }
24735
24857
  const updated = await fetch(`/api/orders/${orderId}`);
24736
24858
  if (updated.ok) setOrder(await updated.json());
24737
24859
  setAssignModalOpen(false);
24738
- toast.success(selectedAssigneeId ? "Order assigned successfully" : "Assignee removed");
24860
+ toast.success(selectedAssigneeId || selectedVendorId ? "Order assigned successfully" : "Assignment removed");
24739
24861
  } catch {
24740
- toast.error("Failed to update assignee");
24862
+ toast.error("Failed to update assignment");
24741
24863
  } finally {
24742
24864
  setSavingAssignee(false);
24743
24865
  }
@@ -25122,7 +25244,19 @@ function OrderDetailPage({ orderId }) {
25122
25244
  className: "min-w-0"
25123
25245
  }, /* @__PURE__ */ React.createElement("dt", {
25124
25246
  className: "text-gray-500"
25125
- }, "Assigned To"), /* @__PURE__ */ React.createElement("dd", {
25247
+ }, "Vendor"), /* @__PURE__ */ React.createElement("dd", {
25248
+ className: "font-medium text-gray-900 flex flex-wrap items-center gap-1.5 mt-0.5"
25249
+ }, order.vendor ? /* @__PURE__ */ React.createElement("span", {
25250
+ className: "inline-flex items-center gap-1 text-xs bg-purple-50 text-purple-800 font-medium px-2 py-0.5 rounded-full border border-purple-200"
25251
+ }, order.vendor.name || `Vendor #${order.vendor.id}`) : order.vendorId ? /* @__PURE__ */ React.createElement("span", {
25252
+ className: "inline-flex items-center gap-1 text-xs bg-purple-50 text-purple-800 font-medium px-2 py-0.5 rounded-full border border-purple-200"
25253
+ }, `Vendor #${order.vendorId}`) : /* @__PURE__ */ React.createElement("span", {
25254
+ className: "text-gray-400 text-xs italic"
25255
+ }, "Platform Default"))), /* @__PURE__ */ React.createElement("div", {
25256
+ className: "min-w-0"
25257
+ }, /* @__PURE__ */ React.createElement("dt", {
25258
+ className: "text-gray-500"
25259
+ }, "Assigned Teammate"), /* @__PURE__ */ React.createElement("dd", {
25126
25260
  className: "font-medium text-gray-900 flex flex-wrap items-center gap-1.5 mt-0.5"
25127
25261
  }, order.assignedUser ? /* @__PURE__ */ React.createElement("span", {
25128
25262
  className: "inline-flex items-center gap-1 text-xs bg-blue-50 text-blue-800 font-medium px-2 py-0.5 rounded-full border border-blue-200"
@@ -25391,7 +25525,7 @@ function OrderDetailPage({ orderId }) {
25391
25525
  className: "text-base font-semibold text-gray-900 flex items-center gap-2"
25392
25526
  }, /* @__PURE__ */ React.createElement(UserCheck, {
25393
25527
  className: "h-5 w-5 text-blue-600"
25394
- }), "Assign Order to Teammate"), /* @__PURE__ */ React.createElement("button", {
25528
+ }), isPlatformAdmin ? "Assign Order (Vendor & Team)" : "Assign Order to Teammate"), /* @__PURE__ */ React.createElement("button", {
25395
25529
  type: "button",
25396
25530
  onClick: /* @__PURE__ */ __name(() => setAssignModalOpen(false), "onClick"),
25397
25531
  className: "text-gray-400 hover:text-gray-600"
@@ -25399,14 +25533,42 @@ function OrderDetailPage({ orderId }) {
25399
25533
  className: "h-5 w-5"
25400
25534
  }))), /* @__PURE__ */ React.createElement("p", {
25401
25535
  className: "text-xs text-gray-500"
25402
- }, "Select a team member to handle this order. When assigned, order status automatically moves to Processing."), loadingAssignees ? /* @__PURE__ */ React.createElement("div", {
25536
+ }, isPlatformAdmin ? "Assign this order to a Vendor or directly to any Vendor's Team Member." : "Select a member of your team to handle this service, or keep it unassigned to your general store."), loadingAssignees ? /* @__PURE__ */ React.createElement("div", {
25403
25537
  className: "flex justify-center py-8"
25404
25538
  }, /* @__PURE__ */ React.createElement(Loader2, {
25405
25539
  className: "h-6 w-6 animate-spin text-blue-600"
25406
25540
  })) : /* @__PURE__ */ React.createElement("div", {
25407
- className: "space-y-2 max-h-64 overflow-y-auto pr-1"
25541
+ className: "space-y-4"
25542
+ }, isPlatformAdmin && vendorsList.length > 0 && /* @__PURE__ */ React.createElement("div", {
25543
+ className: "space-y-1.5"
25544
+ }, /* @__PURE__ */ React.createElement("label", {
25545
+ className: "block text-xs font-semibold text-gray-700"
25546
+ }, "Assigned Vendor"), /* @__PURE__ */ React.createElement("select", {
25547
+ value: selectedVendorId ?? "",
25548
+ onChange: /* @__PURE__ */ __name((e) => {
25549
+ const val = e.target.value ? Number(e.target.value) : null;
25550
+ setSelectedVendorId(val);
25551
+ if (val && selectedAssigneeId) {
25552
+ const assignee = assigneesList.find((a) => a.id === selectedAssigneeId);
25553
+ if (assignee && assignee.vendorId !== val) {
25554
+ setSelectedAssigneeId(null);
25555
+ }
25556
+ }
25557
+ }, "onChange"),
25558
+ className: "w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
25559
+ }, /* @__PURE__ */ React.createElement("option", {
25560
+ value: ""
25561
+ }, "All Vendors / Any Vendor"), vendorsList.map((v) => /* @__PURE__ */ React.createElement("option", {
25562
+ key: v.id,
25563
+ value: v.id
25564
+ }, v.name)))), /* @__PURE__ */ React.createElement("div", {
25565
+ className: "space-y-1.5"
25408
25566
  }, /* @__PURE__ */ React.createElement("label", {
25409
- className: `flex items-center justify-between p-3 rounded-lg border cursor-pointer transition ${selectedAssigneeId === null ? "border-blue-600 bg-blue-50/50" : "border-gray-200 hover:bg-gray-50"}`
25567
+ className: "block text-xs font-semibold text-gray-700"
25568
+ }, isPlatformAdmin ? "Assigned Team Member" : "Select Team Member"), /* @__PURE__ */ React.createElement("div", {
25569
+ className: "space-y-2 max-h-56 overflow-y-auto pr-1"
25570
+ }, /* @__PURE__ */ React.createElement("label", {
25571
+ className: `flex items-center justify-between p-2.5 rounded-lg border cursor-pointer transition ${selectedAssigneeId === null ? "border-blue-600 bg-blue-50/50" : "border-gray-200 hover:bg-gray-50"}`
25410
25572
  }, /* @__PURE__ */ React.createElement("div", {
25411
25573
  className: "flex items-center gap-3"
25412
25574
  }, /* @__PURE__ */ React.createElement("input", {
@@ -25417,26 +25579,40 @@ function OrderDetailPage({ orderId }) {
25417
25579
  className: "text-blue-600"
25418
25580
  }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
25419
25581
  className: "text-sm font-medium text-gray-800"
25420
- }, "Unassigned"), /* @__PURE__ */ React.createElement("p", {
25582
+ }, "Unassigned to specific person"), /* @__PURE__ */ React.createElement("p", {
25421
25583
  className: "text-xs text-gray-400"
25422
- }, "No specific team member")))), assigneesList.map((a) => /* @__PURE__ */ React.createElement("label", {
25584
+ }, selectedVendorId ? "Vendor general queue" : "General queue")))), assigneesList.filter((a) => {
25585
+ if (!isPlatformAdmin) return true;
25586
+ if (selectedVendorId && selectedVendorId !== 1) {
25587
+ return a.vendorId === selectedVendorId;
25588
+ }
25589
+ if (selectedVendorId === 1) {
25590
+ return a.vendorId === 1 || a.vendorId === null;
25591
+ }
25592
+ return true;
25593
+ }).map((a) => /* @__PURE__ */ React.createElement("label", {
25423
25594
  key: a.id,
25424
- className: `flex items-center justify-between p-3 rounded-lg border cursor-pointer transition ${selectedAssigneeId === a.id ? "border-blue-600 bg-blue-50/50" : "border-gray-200 hover:bg-gray-50"}`
25595
+ className: `flex items-center justify-between p-2.5 rounded-lg border cursor-pointer transition ${selectedAssigneeId === a.id ? "border-blue-600 bg-blue-50/50" : "border-gray-200 hover:bg-gray-50"}`
25425
25596
  }, /* @__PURE__ */ React.createElement("div", {
25426
25597
  className: "flex items-center gap-3"
25427
25598
  }, /* @__PURE__ */ React.createElement("input", {
25428
25599
  type: "radio",
25429
25600
  name: "assignee",
25430
25601
  checked: selectedAssigneeId === a.id,
25431
- onChange: /* @__PURE__ */ __name(() => setSelectedAssigneeId(a.id), "onChange"),
25602
+ onChange: /* @__PURE__ */ __name(() => {
25603
+ setSelectedAssigneeId(a.id);
25604
+ if (isPlatformAdmin) {
25605
+ setSelectedVendorId(a.vendorId || 1);
25606
+ }
25607
+ }, "onChange"),
25432
25608
  className: "text-blue-600"
25433
25609
  }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
25434
25610
  className: "text-sm font-medium text-gray-900"
25435
25611
  }, a.name), /* @__PURE__ */ React.createElement("p", {
25436
25612
  className: "text-xs text-gray-500"
25437
- }, a.email))), /* @__PURE__ */ React.createElement("span", {
25438
- className: "text-[11px] font-medium text-gray-500 bg-gray-100 px-2 py-0.5 rounded"
25439
- }, a.role)))), /* @__PURE__ */ React.createElement("div", {
25613
+ }, a.email, isPlatformAdmin && a.vendorName ? ` \u2022 ${a.vendorName}` : ""))), /* @__PURE__ */ React.createElement("span", {
25614
+ className: "text-[11px] font-medium text-gray-600 bg-gray-100 px-2 py-0.5 rounded"
25615
+ }, a.role)))))), /* @__PURE__ */ React.createElement("div", {
25440
25616
  className: "flex justify-end gap-2 pt-2 border-t border-gray-100"
25441
25617
  }, /* @__PURE__ */ React.createElement(Button, {
25442
25618
  variant: "outline",
@@ -25446,7 +25622,7 @@ function OrderDetailPage({ orderId }) {
25446
25622
  onClick: handleSaveAssignee,
25447
25623
  disabled: savingAssignee,
25448
25624
  className: "bg-blue-600 hover:bg-blue-700 text-white"
25449
- }, savingAssignee ? "Saving..." : "Save Assignee")))), completeModalOpen && /* @__PURE__ */ React.createElement("div", {
25625
+ }, savingAssignee ? "Saving..." : "Save Assignment")))), completeModalOpen && /* @__PURE__ */ React.createElement("div", {
25450
25626
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4 animate-in fade-in duration-150"
25451
25627
  }, /* @__PURE__ */ React.createElement("div", {
25452
25628
  className: "bg-white rounded-xl shadow-2xl w-full max-w-md p-6 space-y-4 border border-gray-100"
@@ -27010,6 +27186,10 @@ function OrderPlacementPage({ editOrderId }) {
27010
27186
  toast.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
27011
27187
  return;
27012
27188
  }
27189
+ if (!effectivePhone) {
27190
+ toast.error(placeForSomeoneElse ? "Enter the recipient's phone number" : "Please enter the customer's phone number");
27191
+ return;
27192
+ }
27013
27193
  if (lines.length === 0) {
27014
27194
  toast.error("Add at least one product to the cart");
27015
27195
  return;
@@ -27241,7 +27421,8 @@ function OrderPlacementPage({ editOrderId }) {
27241
27421
  id: "c-phone",
27242
27422
  value: contactPhone,
27243
27423
  onChange: /* @__PURE__ */ __name((e) => setContactPhone(e.target.value), "onChange"),
27244
- placeholder: "phone number"
27424
+ placeholder: "phone number",
27425
+ required: contactId == null && !placeForSomeoneElse
27245
27426
  }))), /* @__PURE__ */ React.createElement("div", {
27246
27427
  className: "flex items-start gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/60 px-4 py-3 mt-1"
27247
27428
  }, /* @__PURE__ */ React.createElement(Checkbox, {
@@ -27317,6 +27498,7 @@ function OrderPlacementPage({ editOrderId }) {
27317
27498
  value: subContactPhone,
27318
27499
  onChange: /* @__PURE__ */ __name((e) => setSubContactPhone(e.target.value), "onChange"),
27319
27500
  placeholder: "phone number",
27501
+ required: placeForSomeoneElse && subContactId == null,
27320
27502
  readOnly: subContactId != null,
27321
27503
  className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
27322
27504
  })))), /* @__PURE__ */ React.createElement("div", {