@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.cjs CHANGED
@@ -895,7 +895,7 @@ var init_admin_config_context = __esm({
895
895
  var CMS_VERSION;
896
896
  var init_cms_version = __esm({
897
897
  "src/lib/cms-version.ts"() {
898
- CMS_VERSION = "1.0.66" ;
898
+ CMS_VERSION = "1.0.68" ;
899
899
  }
900
900
  });
901
901
  function useCatalogCategories(enabled = true) {
@@ -13656,6 +13656,39 @@ __export(SettingsPage_exports, {
13656
13656
  default: () => SettingsPage
13657
13657
  });
13658
13658
  function InvoiceTemplatePreview({ id }) {
13659
+ if (id === "service_detailed") {
13660
+ return /* @__PURE__ */ React.createElement("div", {
13661
+ className: "h-28 rounded-md border border-sky-200 bg-white overflow-hidden shadow-sm p-1.5 space-y-1"
13662
+ }, /* @__PURE__ */ React.createElement("div", {
13663
+ className: "h-4 bg-sky-50 rounded px-1 flex items-center justify-between border border-sky-100"
13664
+ }, /* @__PURE__ */ React.createElement("div", {
13665
+ className: "h-1.5 w-10 bg-sky-700 rounded"
13666
+ }), /* @__PURE__ */ React.createElement("div", {
13667
+ className: "h-1 w-6 bg-slate-400 rounded"
13668
+ })), /* @__PURE__ */ React.createElement("div", {
13669
+ className: "rounded bg-sky-50/70 border border-sky-100 p-1 space-y-0.5"
13670
+ }, /* @__PURE__ */ React.createElement("div", {
13671
+ className: "grid grid-cols-2 gap-1"
13672
+ }, /* @__PURE__ */ React.createElement("div", {
13673
+ className: "h-1 w-full bg-sky-600/70 rounded"
13674
+ }), /* @__PURE__ */ React.createElement("div", {
13675
+ className: "h-1 w-full bg-sky-600/70 rounded"
13676
+ })), /* @__PURE__ */ React.createElement("div", {
13677
+ className: "grid grid-cols-2 gap-1"
13678
+ }, /* @__PURE__ */ React.createElement("div", {
13679
+ className: "h-1 w-full bg-slate-400 rounded"
13680
+ }), /* @__PURE__ */ React.createElement("div", {
13681
+ className: "h-1 w-full bg-slate-400 rounded"
13682
+ }))), /* @__PURE__ */ React.createElement("div", {
13683
+ className: "h-1 w-full bg-slate-100 rounded"
13684
+ }), /* @__PURE__ */ React.createElement("div", {
13685
+ className: "h-1 w-full bg-slate-100 rounded"
13686
+ }), /* @__PURE__ */ React.createElement("div", {
13687
+ className: "flex justify-end pt-0.5"
13688
+ }, /* @__PURE__ */ React.createElement("div", {
13689
+ className: "h-1.5 w-12 bg-sky-700 rounded"
13690
+ })));
13691
+ }
13659
13692
  if (id === "modern") {
13660
13693
  return /* @__PURE__ */ React.createElement("div", {
13661
13694
  className: "h-28 rounded-md border border-slate-200 bg-white overflow-hidden shadow-sm"
@@ -13834,6 +13867,7 @@ function SettingsPage() {
13834
13867
  const [storeSettingsLoading, setStoreSettingsLoading] = React27.useState(true);
13835
13868
  const [currency, setCurrency] = React27.useState(DEFAULT_CURRENCY);
13836
13869
  const [invoiceTemplate, setInvoiceTemplate] = React27.useState("classic");
13870
+ const [invoiceIncludeQr, setInvoiceIncludeQr] = React27.useState(false);
13837
13871
  const [companyLogo, setCompanyLogo] = React27.useState("");
13838
13872
  const [companyName, setCompanyName] = React27.useState("");
13839
13873
  const [companyEmail, setCompanyEmail] = React27.useState("");
@@ -13911,6 +13945,7 @@ function SettingsPage() {
13911
13945
  setStoreEnabled(data.enabled === "true");
13912
13946
  setCurrency(data.currency || DEFAULT_CURRENCY);
13913
13947
  setInvoiceTemplate(data.invoiceTemplate || "classic");
13948
+ setInvoiceIncludeQr(data.invoice_include_qr === "true" || data.invoiceIncludeQr === "true");
13914
13949
  const logo = data.invoiceLogoUrl || data.companyLogo || data.logo || "";
13915
13950
  setCompanyLogo((prev) => logo || prev);
13916
13951
  setCompanyName(data.companyName || data.invoiceCompanyName || data.name || "");
@@ -14076,6 +14111,10 @@ function SettingsPage() {
14076
14111
  value: invoiceTemplate || "classic",
14077
14112
  type: "public"
14078
14113
  },
14114
+ invoice_include_qr: {
14115
+ value: invoiceIncludeQr ? "true" : "false",
14116
+ type: "public"
14117
+ },
14079
14118
  invoiceLogoUrl: {
14080
14119
  value: companyLogo,
14081
14120
  type: "public"
@@ -14544,24 +14583,43 @@ function SettingsPage() {
14544
14583
  placeholder: "e.g. 123 Business Rd, Suite 100\nNew York, NY 10001",
14545
14584
  rows: 3,
14546
14585
  className: "text-sm bg-white"
14547
- })))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
14548
- className: "block text-sm font-semibold text-gray-700 mb-1"
14549
- }, "Invoice PDF template"), /* @__PURE__ */ React.createElement("p", {
14586
+ })))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
14587
+ className: "flex items-center justify-between mb-1"
14588
+ }, /* @__PURE__ */ React.createElement("label", {
14589
+ className: "block text-sm font-semibold text-gray-700"
14590
+ }, "Invoice PDF template"), /* @__PURE__ */ React.createElement("label", {
14591
+ className: "inline-flex items-center gap-2 cursor-pointer select-none text-sm font-semibold text-gray-800 hover:text-gray-950"
14592
+ }, /* @__PURE__ */ React.createElement("input", {
14593
+ type: "checkbox",
14594
+ checked: invoiceIncludeQr,
14595
+ onChange: /* @__PURE__ */ __name((e) => setInvoiceIncludeQr(e.target.checked), "onChange"),
14596
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 accent-blue-600 cursor-pointer"
14597
+ }), /* @__PURE__ */ React.createElement("span", null, "Add QR"))), /* @__PURE__ */ React.createElement("p", {
14550
14598
  className: "text-xs text-gray-500 mb-3"
14551
14599
  }, "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", {
14552
14600
  className: "grid gap-3 sm:grid-cols-2"
14553
14601
  }, INVOICE_TEMPLATE_CARDS.map((opt) => {
14554
14602
  const selected = invoiceTemplate === opt.id;
14555
- return /* @__PURE__ */ React.createElement("button", {
14603
+ return /* @__PURE__ */ React.createElement("div", {
14556
14604
  key: opt.id,
14557
- type: "button",
14558
14605
  onClick: /* @__PURE__ */ __name(() => setInvoiceTemplate(opt.id), "onClick"),
14559
- 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"}`
14606
+ 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"}`
14560
14607
  }, /* @__PURE__ */ React.createElement(InvoiceTemplatePreview, {
14561
14608
  id: opt.id
14562
14609
  }), /* @__PURE__ */ React.createElement("div", {
14563
- className: "text-sm font-semibold text-gray-800 mt-2"
14564
- }, opt.label), /* @__PURE__ */ React.createElement("div", {
14610
+ className: "flex items-center justify-between mt-2"
14611
+ }, /* @__PURE__ */ React.createElement("div", {
14612
+ className: "text-sm font-semibold text-gray-800"
14613
+ }, opt.label), /* @__PURE__ */ React.createElement("button", {
14614
+ type: "button",
14615
+ onClick: /* @__PURE__ */ __name((e) => {
14616
+ e.stopPropagation();
14617
+ window.open(`/api/settings/invoice-preview?template=${encodeURIComponent(opt.id)}&qr=${invoiceIncludeQr ? "1" : "0"}`, "_blank");
14618
+ }, "onClick"),
14619
+ 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"
14620
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Eye, {
14621
+ className: "w-3 h-3"
14622
+ }), "Preview")), /* @__PURE__ */ React.createElement("div", {
14565
14623
  className: "text-xs text-gray-500 mt-0.5"
14566
14624
  }, opt.description));
14567
14625
  }))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
@@ -14790,6 +14848,11 @@ var init_SettingsPage = __esm({
14790
14848
  id: "bold",
14791
14849
  label: "Bold",
14792
14850
  description: "Strong header band and clear payment summary."
14851
+ },
14852
+ {
14853
+ id: "service_detailed",
14854
+ label: "Service Detailed",
14855
+ description: "Includes order date, service date, slot, and assigned technician."
14793
14856
  }
14794
14857
  ];
14795
14858
  __name(InvoiceTemplatePreview, "InvoiceTemplatePreview");
@@ -23279,6 +23342,7 @@ function VendorTeamPage() {
23279
23342
  const [inviteDialog, setInviteDialog] = React27.useState(null);
23280
23343
  const [sendingInviteEmail, setSendingInviteEmail] = React27.useState(false);
23281
23344
  const [linkCopied, setLinkCopied] = React27.useState(false);
23345
+ const [resendingUserId, setResendingUserId] = React27.useState(null);
23282
23346
  const assignableRoles = roles.filter((r) => !r.isOwnerRole);
23283
23347
  const load = React27.useCallback(async () => {
23284
23348
  setLoading(true);
@@ -23357,6 +23421,31 @@ function VendorTeamPage() {
23357
23421
  setInviteDialog(null);
23358
23422
  setLinkCopied(false);
23359
23423
  }, "closeInviteDialog");
23424
+ const handleResendInvite = /* @__PURE__ */ __name(async (userId) => {
23425
+ setResendingUserId(userId);
23426
+ try {
23427
+ const res = await fetch("/api/admin/vendor/team/send-invite", {
23428
+ method: "POST",
23429
+ headers: {
23430
+ "Content-Type": "application/json"
23431
+ },
23432
+ body: JSON.stringify({
23433
+ userId
23434
+ })
23435
+ });
23436
+ const data = await res.json();
23437
+ if (!res.ok) {
23438
+ sonner.toast.error(data.error || data.message || "Failed to resend invite");
23439
+ return;
23440
+ }
23441
+ sonner.toast.success(data.message || "Invite email sent");
23442
+ await load();
23443
+ } catch {
23444
+ sonner.toast.error("Failed to resend invite");
23445
+ } finally {
23446
+ setResendingUserId(null);
23447
+ }
23448
+ }, "handleResendInvite");
23360
23449
  if (!canManage) {
23361
23450
  return /* @__PURE__ */ React27__namespace.default.createElement("div", {
23362
23451
  className: "min-w-0 rounded-lg bg-white shadow-md"
@@ -23528,12 +23617,26 @@ function VendorTeamPage() {
23528
23617
  value: r.id
23529
23618
  }, r.name)))), /* @__PURE__ */ React27__namespace.default.createElement("td", {
23530
23619
  className: "px-3 py-2 text-right"
23531
- }, !m.isOwnerRole && /* @__PURE__ */ React27__namespace.default.createElement(Button, {
23620
+ }, /* @__PURE__ */ React27__namespace.default.createElement("div", {
23621
+ className: "flex items-center justify-end gap-1.5"
23622
+ }, !m.isOwnerRole && String(m.inviteStatus ?? "") === "pending" && /* @__PURE__ */ React27__namespace.default.createElement(Button, {
23623
+ type: "button",
23624
+ variant: "outline",
23625
+ size: "icon",
23626
+ className: "h-7 w-7",
23627
+ disabled: resendingUserId === m.userId,
23628
+ onClick: /* @__PURE__ */ __name(() => void handleResendInvite(m.userId), "onClick"),
23629
+ title: "Resend invite"
23630
+ }, /* @__PURE__ */ React27__namespace.default.createElement(LucideIcons.RefreshCw, {
23631
+ className: `h-3.5 w-3.5 ${resendingUserId === m.userId ? "animate-spin text-blue-600" : ""}`
23632
+ }), /* @__PURE__ */ React27__namespace.default.createElement("span", {
23633
+ className: "sr-only"
23634
+ }, "Resend invite")), !m.isOwnerRole && /* @__PURE__ */ React27__namespace.default.createElement(Button, {
23532
23635
  type: "button",
23533
23636
  variant: "ghost",
23534
23637
  size: "sm",
23535
23638
  onClick: /* @__PURE__ */ __name(() => handleRemove(m.userId), "onClick")
23536
- }, "Remove"))))))), /* @__PURE__ */ React27__namespace.default.createElement("form", {
23639
+ }, "Remove")))))))), /* @__PURE__ */ React27__namespace.default.createElement("form", {
23537
23640
  onSubmit: handleAdd,
23538
23641
  className: "space-y-4 rounded-lg border border-gray-200 p-4"
23539
23642
  }, /* @__PURE__ */ React27__namespace.default.createElement("h2", {
@@ -24598,7 +24701,10 @@ function OrderDetailPage({ orderId }) {
24598
24701
  const [cancelModal, setCancelModal] = React27.useState(null);
24599
24702
  const [assignModalOpen, setAssignModalOpen] = React27.useState(false);
24600
24703
  const [assigneesList, setAssigneesList] = React27.useState([]);
24704
+ const [vendorsList, setVendorsList] = React27.useState([]);
24705
+ const [isPlatformAdmin, setIsPlatformAdmin] = React27.useState(false);
24601
24706
  const [loadingAssignees, setLoadingAssignees] = React27.useState(false);
24707
+ const [selectedVendorId, setSelectedVendorId] = React27.useState(null);
24602
24708
  const [selectedAssigneeId, setSelectedAssigneeId] = React27.useState(null);
24603
24709
  const [savingAssignee, setSavingAssignee] = React27.useState(false);
24604
24710
  const [completeModalOpen, setCompleteModalOpen] = React27.useState(false);
@@ -24698,8 +24804,9 @@ function OrderDetailPage({ orderId }) {
24698
24804
  async function handleStartProcessing() {
24699
24805
  if (!order || startingProcessing) return;
24700
24806
  const currentAssigneeId = order.assignedUserId ?? order.assignedUser?.id ?? null;
24701
- if (!currentAssigneeId) {
24702
- sonner.toast.info("Please assign a teammate before starting order processing.");
24807
+ const currentVendorId = order.vendorId ?? order.vendor?.id ?? null;
24808
+ if (!currentAssigneeId && !currentVendorId) {
24809
+ sonner.toast.info("Please assign a vendor or teammate before starting order processing.");
24703
24810
  handleOpenAssignModal();
24704
24811
  return;
24705
24812
  }
@@ -24712,7 +24819,9 @@ function OrderDetailPage({ orderId }) {
24712
24819
  },
24713
24820
  body: JSON.stringify({
24714
24821
  status: "processing",
24715
- assignedUserId: currentAssigneeId
24822
+ ...currentAssigneeId ? {
24823
+ assignedUserId: currentAssigneeId
24824
+ } : {}
24716
24825
  })
24717
24826
  });
24718
24827
  const data = await res.json().catch(() => ({}));
@@ -24734,14 +24843,19 @@ function OrderDetailPage({ orderId }) {
24734
24843
  setAssignModalOpen(true);
24735
24844
  setLoadingAssignees(true);
24736
24845
  setSelectedAssigneeId(order?.assignedUserId ?? null);
24846
+ setSelectedVendorId(order?.vendorId ?? null);
24737
24847
  try {
24738
24848
  const res = await fetch(`/api/orders/${orderId}/eligible-assignees`);
24739
24849
  if (res.ok) {
24740
24850
  const data = await res.json();
24741
24851
  setAssigneesList(data.assignees ?? []);
24852
+ setVendorsList(data.vendors ?? []);
24853
+ setIsPlatformAdmin(Boolean(data.isPlatformAdmin));
24854
+ if (data.currentVendorId != null) setSelectedVendorId(data.currentVendorId);
24855
+ if (data.currentAssignedUserId != null) setSelectedAssigneeId(data.currentAssignedUserId);
24742
24856
  }
24743
24857
  } catch {
24744
- sonner.toast.error("Failed to load eligible team members");
24858
+ sonner.toast.error("Failed to load eligible assignees");
24745
24859
  } finally {
24746
24860
  setLoadingAssignees(false);
24747
24861
  }
@@ -24754,6 +24868,14 @@ function OrderDetailPage({ orderId }) {
24754
24868
  const bodyPayload = {
24755
24869
  assignedUserId: selectedAssigneeId
24756
24870
  };
24871
+ if (isPlatformAdmin) {
24872
+ const chosenAssignee = assigneesList.find((a) => a.id === selectedAssigneeId);
24873
+ if (chosenAssignee && chosenAssignee.vendorId === null) {
24874
+ bodyPayload.vendorId = 1;
24875
+ } else {
24876
+ bodyPayload.vendorId = chosenAssignee?.vendorId ?? (selectedVendorId || 1);
24877
+ }
24878
+ }
24757
24879
  const res = await fetch(`/api/orders/${orderId}`, {
24758
24880
  method: "PUT",
24759
24881
  headers: {
@@ -24763,15 +24885,15 @@ function OrderDetailPage({ orderId }) {
24763
24885
  });
24764
24886
  if (!res.ok) {
24765
24887
  const err = await res.json().catch(() => ({}));
24766
- sonner.toast.error(err.error ?? "Failed to update assignee");
24888
+ sonner.toast.error(err.error ?? "Failed to update assignment");
24767
24889
  return;
24768
24890
  }
24769
24891
  const updated = await fetch(`/api/orders/${orderId}`);
24770
24892
  if (updated.ok) setOrder(await updated.json());
24771
24893
  setAssignModalOpen(false);
24772
- sonner.toast.success(selectedAssigneeId ? "Order assigned successfully" : "Assignee removed");
24894
+ sonner.toast.success(selectedAssigneeId || selectedVendorId ? "Order assigned successfully" : "Assignment removed");
24773
24895
  } catch {
24774
- sonner.toast.error("Failed to update assignee");
24896
+ sonner.toast.error("Failed to update assignment");
24775
24897
  } finally {
24776
24898
  setSavingAssignee(false);
24777
24899
  }
@@ -25156,7 +25278,19 @@ function OrderDetailPage({ orderId }) {
25156
25278
  className: "min-w-0"
25157
25279
  }, /* @__PURE__ */ React.createElement("dt", {
25158
25280
  className: "text-gray-500"
25159
- }, "Assigned To"), /* @__PURE__ */ React.createElement("dd", {
25281
+ }, "Vendor"), /* @__PURE__ */ React.createElement("dd", {
25282
+ className: "font-medium text-gray-900 flex flex-wrap items-center gap-1.5 mt-0.5"
25283
+ }, order.vendor ? /* @__PURE__ */ React.createElement("span", {
25284
+ 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"
25285
+ }, order.vendor.name || `Vendor #${order.vendor.id}`) : order.vendorId ? /* @__PURE__ */ React.createElement("span", {
25286
+ 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"
25287
+ }, `Vendor #${order.vendorId}`) : /* @__PURE__ */ React.createElement("span", {
25288
+ className: "text-gray-400 text-xs italic"
25289
+ }, "Platform Default"))), /* @__PURE__ */ React.createElement("div", {
25290
+ className: "min-w-0"
25291
+ }, /* @__PURE__ */ React.createElement("dt", {
25292
+ className: "text-gray-500"
25293
+ }, "Assigned Teammate"), /* @__PURE__ */ React.createElement("dd", {
25160
25294
  className: "font-medium text-gray-900 flex flex-wrap items-center gap-1.5 mt-0.5"
25161
25295
  }, order.assignedUser ? /* @__PURE__ */ React.createElement("span", {
25162
25296
  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"
@@ -25425,7 +25559,7 @@ function OrderDetailPage({ orderId }) {
25425
25559
  className: "text-base font-semibold text-gray-900 flex items-center gap-2"
25426
25560
  }, /* @__PURE__ */ React.createElement(LucideIcons.UserCheck, {
25427
25561
  className: "h-5 w-5 text-blue-600"
25428
- }), "Assign Order to Teammate"), /* @__PURE__ */ React.createElement("button", {
25562
+ }), isPlatformAdmin ? "Assign Order (Vendor & Team)" : "Assign Order to Teammate"), /* @__PURE__ */ React.createElement("button", {
25429
25563
  type: "button",
25430
25564
  onClick: /* @__PURE__ */ __name(() => setAssignModalOpen(false), "onClick"),
25431
25565
  className: "text-gray-400 hover:text-gray-600"
@@ -25433,14 +25567,42 @@ function OrderDetailPage({ orderId }) {
25433
25567
  className: "h-5 w-5"
25434
25568
  }))), /* @__PURE__ */ React.createElement("p", {
25435
25569
  className: "text-xs text-gray-500"
25436
- }, "Select a team member to handle this order. When assigned, order status automatically moves to Processing."), loadingAssignees ? /* @__PURE__ */ React.createElement("div", {
25570
+ }, 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", {
25437
25571
  className: "flex justify-center py-8"
25438
25572
  }, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
25439
25573
  className: "h-6 w-6 animate-spin text-blue-600"
25440
25574
  })) : /* @__PURE__ */ React.createElement("div", {
25441
- className: "space-y-2 max-h-64 overflow-y-auto pr-1"
25575
+ className: "space-y-4"
25576
+ }, isPlatformAdmin && vendorsList.length > 0 && /* @__PURE__ */ React.createElement("div", {
25577
+ className: "space-y-1.5"
25578
+ }, /* @__PURE__ */ React.createElement("label", {
25579
+ className: "block text-xs font-semibold text-gray-700"
25580
+ }, "Assigned Vendor"), /* @__PURE__ */ React.createElement("select", {
25581
+ value: selectedVendorId ?? "",
25582
+ onChange: /* @__PURE__ */ __name((e) => {
25583
+ const val = e.target.value ? Number(e.target.value) : null;
25584
+ setSelectedVendorId(val);
25585
+ if (val && selectedAssigneeId) {
25586
+ const assignee = assigneesList.find((a) => a.id === selectedAssigneeId);
25587
+ if (assignee && assignee.vendorId !== val) {
25588
+ setSelectedAssigneeId(null);
25589
+ }
25590
+ }
25591
+ }, "onChange"),
25592
+ 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"
25593
+ }, /* @__PURE__ */ React.createElement("option", {
25594
+ value: ""
25595
+ }, "All Vendors / Any Vendor"), vendorsList.map((v) => /* @__PURE__ */ React.createElement("option", {
25596
+ key: v.id,
25597
+ value: v.id
25598
+ }, v.name)))), /* @__PURE__ */ React.createElement("div", {
25599
+ className: "space-y-1.5"
25442
25600
  }, /* @__PURE__ */ React.createElement("label", {
25443
- 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"}`
25601
+ className: "block text-xs font-semibold text-gray-700"
25602
+ }, isPlatformAdmin ? "Assigned Team Member" : "Select Team Member"), /* @__PURE__ */ React.createElement("div", {
25603
+ className: "space-y-2 max-h-56 overflow-y-auto pr-1"
25604
+ }, /* @__PURE__ */ React.createElement("label", {
25605
+ 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"}`
25444
25606
  }, /* @__PURE__ */ React.createElement("div", {
25445
25607
  className: "flex items-center gap-3"
25446
25608
  }, /* @__PURE__ */ React.createElement("input", {
@@ -25451,26 +25613,40 @@ function OrderDetailPage({ orderId }) {
25451
25613
  className: "text-blue-600"
25452
25614
  }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
25453
25615
  className: "text-sm font-medium text-gray-800"
25454
- }, "Unassigned"), /* @__PURE__ */ React.createElement("p", {
25616
+ }, "Unassigned to specific person"), /* @__PURE__ */ React.createElement("p", {
25455
25617
  className: "text-xs text-gray-400"
25456
- }, "No specific team member")))), assigneesList.map((a) => /* @__PURE__ */ React.createElement("label", {
25618
+ }, selectedVendorId ? "Vendor general queue" : "General queue")))), assigneesList.filter((a) => {
25619
+ if (!isPlatformAdmin) return true;
25620
+ if (selectedVendorId && selectedVendorId !== 1) {
25621
+ return a.vendorId === selectedVendorId;
25622
+ }
25623
+ if (selectedVendorId === 1) {
25624
+ return a.vendorId === 1 || a.vendorId === null;
25625
+ }
25626
+ return true;
25627
+ }).map((a) => /* @__PURE__ */ React.createElement("label", {
25457
25628
  key: a.id,
25458
- 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"}`
25629
+ 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"}`
25459
25630
  }, /* @__PURE__ */ React.createElement("div", {
25460
25631
  className: "flex items-center gap-3"
25461
25632
  }, /* @__PURE__ */ React.createElement("input", {
25462
25633
  type: "radio",
25463
25634
  name: "assignee",
25464
25635
  checked: selectedAssigneeId === a.id,
25465
- onChange: /* @__PURE__ */ __name(() => setSelectedAssigneeId(a.id), "onChange"),
25636
+ onChange: /* @__PURE__ */ __name(() => {
25637
+ setSelectedAssigneeId(a.id);
25638
+ if (isPlatformAdmin) {
25639
+ setSelectedVendorId(a.vendorId || 1);
25640
+ }
25641
+ }, "onChange"),
25466
25642
  className: "text-blue-600"
25467
25643
  }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
25468
25644
  className: "text-sm font-medium text-gray-900"
25469
25645
  }, a.name), /* @__PURE__ */ React.createElement("p", {
25470
25646
  className: "text-xs text-gray-500"
25471
- }, a.email))), /* @__PURE__ */ React.createElement("span", {
25472
- className: "text-[11px] font-medium text-gray-500 bg-gray-100 px-2 py-0.5 rounded"
25473
- }, a.role)))), /* @__PURE__ */ React.createElement("div", {
25647
+ }, a.email, isPlatformAdmin && a.vendorName ? ` \u2022 ${a.vendorName}` : ""))), /* @__PURE__ */ React.createElement("span", {
25648
+ className: "text-[11px] font-medium text-gray-600 bg-gray-100 px-2 py-0.5 rounded"
25649
+ }, a.role)))))), /* @__PURE__ */ React.createElement("div", {
25474
25650
  className: "flex justify-end gap-2 pt-2 border-t border-gray-100"
25475
25651
  }, /* @__PURE__ */ React.createElement(Button, {
25476
25652
  variant: "outline",
@@ -25480,7 +25656,7 @@ function OrderDetailPage({ orderId }) {
25480
25656
  onClick: handleSaveAssignee,
25481
25657
  disabled: savingAssignee,
25482
25658
  className: "bg-blue-600 hover:bg-blue-700 text-white"
25483
- }, savingAssignee ? "Saving..." : "Save Assignee")))), completeModalOpen && /* @__PURE__ */ React.createElement("div", {
25659
+ }, savingAssignee ? "Saving..." : "Save Assignment")))), completeModalOpen && /* @__PURE__ */ React.createElement("div", {
25484
25660
  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"
25485
25661
  }, /* @__PURE__ */ React.createElement("div", {
25486
25662
  className: "bg-white rounded-xl shadow-2xl w-full max-w-md p-6 space-y-4 border border-gray-100"
@@ -27044,6 +27220,10 @@ function OrderPlacementPage({ editOrderId }) {
27044
27220
  sonner.toast.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
27045
27221
  return;
27046
27222
  }
27223
+ if (!effectivePhone) {
27224
+ sonner.toast.error(placeForSomeoneElse ? "Enter the recipient's phone number" : "Please enter the customer's phone number");
27225
+ return;
27226
+ }
27047
27227
  if (lines.length === 0) {
27048
27228
  sonner.toast.error("Add at least one product to the cart");
27049
27229
  return;
@@ -27275,7 +27455,8 @@ function OrderPlacementPage({ editOrderId }) {
27275
27455
  id: "c-phone",
27276
27456
  value: contactPhone,
27277
27457
  onChange: /* @__PURE__ */ __name((e) => setContactPhone(e.target.value), "onChange"),
27278
- placeholder: "phone number"
27458
+ placeholder: "phone number",
27459
+ required: contactId == null && !placeForSomeoneElse
27279
27460
  }))), /* @__PURE__ */ React.createElement("div", {
27280
27461
  className: "flex items-start gap-3 rounded-lg border border-dashed border-gray-300 bg-gray-50/60 px-4 py-3 mt-1"
27281
27462
  }, /* @__PURE__ */ React.createElement(Checkbox, {
@@ -27351,6 +27532,7 @@ function OrderPlacementPage({ editOrderId }) {
27351
27532
  value: subContactPhone,
27352
27533
  onChange: /* @__PURE__ */ __name((e) => setSubContactPhone(e.target.value), "onChange"),
27353
27534
  placeholder: "phone number",
27535
+ required: placeForSomeoneElse && subContactId == null,
27354
27536
  readOnly: subContactId != null,
27355
27537
  className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
27356
27538
  })))), /* @__PURE__ */ React.createElement("div", {