@infuro/cms-core 1.0.67 → 1.0.69

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 (150) hide show
  1. package/dist/{OrderTrackPage-W3J6WIG2.js → OrderTrackPage-VBZUVZOU.js} +1 -1
  2. package/dist/{OrderTrackPage-Z6FCJQYY.cjs → OrderTrackPage-VFIXWJOW.cjs} +4 -4
  3. package/dist/admin.cjs +121 -12
  4. package/dist/admin.js +121 -12
  5. package/dist/api.cjs +57 -54
  6. package/dist/api.js +24 -21
  7. package/dist/auth.cjs +62 -62
  8. package/dist/auth.js +6 -6
  9. package/dist/{chunk-XJNNOSJR.js → chunk-2BNVRFUQ.js} +1 -1
  10. package/dist/chunk-2JHGIWH7.cjs +2700 -0
  11. package/dist/{chunk-3DZRIZOD.cjs → chunk-3ASNJS2H.cjs} +3 -3
  12. package/dist/{chunk-7NMT3GBR.cjs → chunk-3LQS4ATQ.cjs} +4 -4
  13. package/dist/{chunk-GWDI752Q.js → chunk-3XCTGADT.js} +1 -1
  14. package/dist/chunk-47G65M5Q.cjs +18 -0
  15. package/dist/{chunk-XFDIIVZB.cjs → chunk-4MNVIGVJ.cjs} +11 -11
  16. package/dist/{chunk-OY2YTBMP.cjs → chunk-4WZNRVEZ.cjs} +3 -3
  17. package/dist/{chunk-OVTOP42W.js → chunk-53AMBXMM.js} +1 -1
  18. package/dist/chunk-5BKT4CS5.js +28 -0
  19. package/dist/chunk-5DSY3GQI.js +16 -0
  20. package/dist/{chunk-AYERBA7I.js → chunk-5NVGWJSY.js} +1 -1
  21. package/dist/{chunk-HF3L2GIT.cjs → chunk-5YMKJ3TH.cjs} +16 -16
  22. package/dist/{chunk-WFMVD567.cjs → chunk-6MM5OMRL.cjs} +11 -11
  23. package/dist/{chunk-5MZFQRDW.cjs → chunk-747MJJCZ.cjs} +147 -147
  24. package/dist/{chunk-SYBOCAWB.js → chunk-7QJI56OL.js} +1 -1
  25. package/dist/{chunk-DBPSJYLZ.js → chunk-BK5XW5XH.js} +1 -1
  26. package/dist/chunk-BQQMTQ4C.cjs +455 -0
  27. package/dist/{chunk-6YOQ7G5O.js → chunk-CFUSYGSA.js} +1 -1
  28. package/dist/{chunk-OOTLNH63.cjs → chunk-CIZZX57T.cjs} +2 -2
  29. package/dist/{chunk-7L6KWI7S.cjs → chunk-CTTV375J.cjs} +13 -13
  30. package/dist/{chunk-ZY64VJMS.js → chunk-D4LR3S77.js} +2 -2
  31. package/dist/{chunk-GLLCLRCQ.js → chunk-DBBYLSQP.js} +179 -49
  32. package/dist/{chunk-5NOZSG6J.js → chunk-DWNQTFJ5.js} +2 -2
  33. package/dist/{chunk-2IAXTKQN.cjs → chunk-DZNWS2MM.cjs} +2 -2
  34. package/dist/chunk-E62LKM6Z.cjs +49 -0
  35. package/dist/{chunk-CRFV5WJK.js → chunk-ECNYZG6T.js} +1 -1
  36. package/dist/{chunk-TZEMLHSP.cjs → chunk-EYUBL7YH.cjs} +7 -7
  37. package/dist/{chunk-WMMZZRDJ.cjs → chunk-HGR4IA7I.cjs} +18 -18
  38. package/dist/{chunk-TJ2MIQUT.cjs → chunk-JRW3GQD4.cjs} +4 -4
  39. package/dist/{chunk-3K5AIEIZ.js → chunk-JYRFSFXH.js} +1 -1
  40. package/dist/chunk-K6RXCLD5.js +45 -0
  41. package/dist/{chunk-TU23GJPJ.js → chunk-LJ5C4RBF.js} +3 -3
  42. package/dist/{chunk-O4AFPDQ4.cjs → chunk-LXWF6T7F.cjs} +33 -33
  43. package/dist/{chunk-EIZKW2PF.js → chunk-LY7CDNC6.js} +1 -1
  44. package/dist/{chunk-PA6YDMFZ.cjs → chunk-M5QDJOUP.cjs} +12 -12
  45. package/dist/{chunk-MQBT33IV.js → chunk-MGT4DJ2D.js} +1 -1
  46. package/dist/{chunk-2ISSXYBZ.js → chunk-MJDNS324.js} +5 -5
  47. package/dist/{chunk-H3IVLIPR.cjs → chunk-OXFC3DAM.cjs} +4 -4
  48. package/dist/chunk-PQJIJ4ZX.js +445 -0
  49. package/dist/{chunk-HY3AXLOI.cjs → chunk-PRXVSSIF.cjs} +13 -13
  50. package/dist/{chunk-TDV6EJHV.js → chunk-PRZOLCFW.js} +2 -2
  51. package/dist/{chunk-BVLN75LP.cjs → chunk-QL44NCZC.cjs} +1221 -1091
  52. package/dist/{chunk-VM6OVUUM.cjs → chunk-QN6PZLAP.cjs} +40 -40
  53. package/dist/{chunk-OV5TRZET.cjs → chunk-QXAQ3V7R.cjs} +27 -27
  54. package/dist/{chunk-NV5IRHI3.js → chunk-RBKVMHBH.js} +9 -9
  55. package/dist/{chunk-UPLVMVRX.cjs → chunk-RQCXRCYM.cjs} +2 -2
  56. package/dist/{chunk-WUQAOTHA.js → chunk-SERRQ736.js} +1 -1
  57. package/dist/{chunk-SS3K7OIM.cjs → chunk-SWSTGV4F.cjs} +81 -81
  58. package/dist/{chunk-RCE5SJBA.js → chunk-T47VP2ZT.js} +3 -3
  59. package/dist/{chunk-FLUF2GZH.js → chunk-WHMIWJL7.js} +1 -1
  60. package/dist/{chunk-JC6DLWTE.js → chunk-WQZ4AH2P.js} +1 -1
  61. package/dist/{chunk-D5FBNKQM.cjs → chunk-WXH3GMCF.cjs} +8 -8
  62. package/dist/chunk-XHPRD45G.cjs +32 -0
  63. package/dist/{chunk-THL5JDWJ.cjs → chunk-Y54WDY2O.cjs} +2 -2
  64. package/dist/{chunk-YRCKEGL2.js → chunk-YDMHG6BA.js} +1 -1
  65. package/dist/chunk-YHVA5NHI.js +2698 -0
  66. package/dist/{chunk-JXF23MPG.js → chunk-ZMIMKNSQ.js} +1 -1
  67. package/dist/cli.cjs +10 -10
  68. package/dist/cli.js +1 -1
  69. package/dist/email-queue-BJDH2ID7.cjs +29 -0
  70. package/dist/email-queue-MWP4R67H.js +8 -0
  71. package/dist/email-service-6JODEMUA.js +3 -0
  72. package/dist/email-service-VA4Q4ZRB.cjs +28 -0
  73. package/dist/emit-order-notification-trigger-X36V4DOH.cjs +16 -0
  74. package/dist/emit-order-notification-trigger-XKN2TWVF.js +3 -0
  75. package/dist/erp-config-enabled-32XTHBBT.cjs +11 -0
  76. package/dist/erp-config-enabled-CASE5YVI.js +2 -0
  77. package/dist/erp-order-invoice-5O42ZKC5.cjs +28 -0
  78. package/dist/erp-order-invoice-JEQKFXG4.js +7 -0
  79. package/dist/{event-order-defaults-DU7V3YND.cjs → event-order-defaults-TR45WAQQ.cjs} +10 -10
  80. package/dist/{event-order-defaults-H4RT7NMR.js → event-order-defaults-VXYO6NHT.js} +2 -2
  81. package/dist/generate-local-invoice-pdf-2NCA2WBL.cjs +12 -0
  82. package/dist/generate-local-invoice-pdf-XUH6GYEJ.js +3 -0
  83. package/dist/hooks.cjs +24 -24
  84. package/dist/hooks.js +2 -2
  85. package/dist/index.cjs +497 -494
  86. package/dist/index.d.cts +7 -1
  87. package/dist/index.d.ts +7 -1
  88. package/dist/index.js +39 -36
  89. package/dist/interpolate-KD37IRF2.js +2 -0
  90. package/dist/interpolate-WP6OSJHN.cjs +11 -0
  91. package/dist/invoice-templates-2ESQ7K4N.cjs +19 -0
  92. package/dist/invoice-templates-3AXTXERZ.js +2 -0
  93. package/dist/middleware.cjs +4 -4
  94. package/dist/middleware.js +2 -2
  95. package/dist/{order-assignees-handlers-L3RVKUBS.js → order-assignees-handlers-F7WOZHOG.js} +1 -1
  96. package/dist/{order-assignees-handlers-KF7RMTV5.cjs → order-assignees-handlers-JEJ5IDID.cjs} +3 -3
  97. package/dist/{order-completion-otp-handlers-HFGCPC4O.js → order-completion-otp-handlers-FIW7PZ6W.js} +12 -9
  98. package/dist/{order-completion-otp-handlers-DZAXK4GQ.cjs → order-completion-otp-handlers-LNAZTMTS.cjs} +25 -22
  99. package/dist/{order-inventory-76V4XIGW.js → order-inventory-R3AU6N4V.js} +2 -2
  100. package/dist/{order-inventory-2MYRKEPC.cjs → order-inventory-UUFPWLBW.cjs} +10 -10
  101. package/dist/order-notification-dispatcher-FS54ANAV.js +13 -0
  102. package/dist/order-notification-dispatcher-GG5C4LKZ.cjs +38 -0
  103. package/dist/paid-order-erp-GRXR2OG6.js +3 -0
  104. package/dist/paid-order-erp-X5QHPI23.cjs +12 -0
  105. package/dist/pg-boss-service-CMW3KQJM.js +2 -0
  106. package/dist/pg-boss-service-GA6ZVD5G.cjs +15 -0
  107. package/dist/{razorpay-U23LGY72.cjs → razorpay-GP2DXVP2.cjs} +2 -2
  108. package/dist/{razorpay-KLO2KNCB.js → razorpay-I3G5LNYH.js} +1 -1
  109. package/dist/{rbac-debug-db-KWV7D5PQ.cjs → rbac-debug-db-2ZI3XKA4.cjs} +4 -4
  110. package/dist/{rbac-debug-db-DFZWZ6GV.js → rbac-debug-db-IRKT6G62.js} +2 -2
  111. package/dist/resolve-invoice-asset-url-64QQUVC3.js +2 -0
  112. package/dist/resolve-invoice-asset-url-J7WAMD26.cjs +11 -0
  113. package/dist/retire-soft-deleted-unique-DZALT537.cjs +15 -0
  114. package/dist/{retire-soft-deleted-unique-NXQIH4BC.js → retire-soft-deleted-unique-F25KZBZK.js} +2 -2
  115. package/dist/sms-defaults-DSO3M26Y.js +2 -0
  116. package/dist/{sms-defaults-KCOPKQBA.cjs → sms-defaults-GDFILHHR.cjs} +5 -5
  117. package/dist/{sms-notification-templates-handlers-SJLO7JGZ.js → sms-notification-templates-handlers-ZGDCVS5Z.js} +1 -1
  118. package/dist/{sms-notification-templates-handlers-YSB3L2PK.cjs → sms-notification-templates-handlers-ZKLKFRFZ.cjs} +3 -3
  119. package/dist/{stripe-VU6OEG2D.cjs → stripe-2APRZHKU.cjs} +2 -2
  120. package/dist/{stripe-4FD27QVJ.js → stripe-7CO2ETTN.js} +1 -1
  121. package/dist/theme.cjs +10 -10
  122. package/dist/theme.js +3 -3
  123. package/dist/vendor-invite-status-45ZCWKCX.js +2 -0
  124. package/dist/{vendor-invite-status-77O7ZQ3U.cjs → vendor-invite-status-AT2E4FUA.cjs} +5 -5
  125. package/package.json +2 -1
  126. package/dist/chunk-GLD263KW.cjs +0 -862
  127. package/dist/chunk-OPJEV44S.js +0 -847
  128. package/dist/chunk-SHUYVCID.js +0 -4
  129. package/dist/chunk-USNT2KNT.cjs +0 -6
  130. package/dist/email-queue-4OY45JIU.cjs +0 -26
  131. package/dist/email-queue-HGXB2FIS.js +0 -5
  132. package/dist/email-service-5O24BSFR.cjs +0 -28
  133. package/dist/email-service-ADDF52PJ.js +0 -3
  134. package/dist/emit-order-notification-trigger-EJJZ6XTS.js +0 -3
  135. package/dist/emit-order-notification-trigger-ZD5YN3JM.cjs +0 -16
  136. package/dist/erp-config-enabled-CUMQ6N2V.cjs +0 -11
  137. package/dist/erp-config-enabled-T37X7T34.js +0 -2
  138. package/dist/erp-order-invoice-H6HCJ7YS.js +0 -4
  139. package/dist/erp-order-invoice-YUSPZ7CE.cjs +0 -25
  140. package/dist/interpolate-WAKPN56R.cjs +0 -11
  141. package/dist/interpolate-WDUWDF3I.js +0 -2
  142. package/dist/order-notification-dispatcher-ECPFI7CD.js +0 -10
  143. package/dist/order-notification-dispatcher-LL7ETKLU.cjs +0 -35
  144. package/dist/paid-order-erp-3USEG6WL.js +0 -3
  145. package/dist/paid-order-erp-FSQ3GSXE.cjs +0 -12
  146. package/dist/pg-boss-service-BDGOKM2T.cjs +0 -15
  147. package/dist/pg-boss-service-WCBJD4JB.js +0 -2
  148. package/dist/retire-soft-deleted-unique-5VXBA5XX.cjs +0 -15
  149. package/dist/sms-defaults-2NL24H57.js +0 -2
  150. package/dist/vendor-invite-status-PWJ3DE76.js +0 -2
@@ -1,4 +1,4 @@
1
- import { __name } from './chunk-SHUYVCID.js';
1
+ import { __name } from './chunk-5BKT4CS5.js';
2
2
 
3
3
  // src/admin/pages/OrderTrackPage.ts
4
4
  function renderOrderTrackingPage(order) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
3
+ var chunkXHPRD45G_cjs = require('./chunk-XHPRD45G.cjs');
4
4
 
5
5
  // src/admin/pages/OrderTrackPage.ts
6
6
  function renderOrderTrackingPage(order) {
@@ -14,7 +14,7 @@ function renderOrderTrackingPage(order) {
14
14
  minimumFractionDigits: 2
15
15
  }).format(Number(amount));
16
16
  }
17
- chunkUSNT2KNT_cjs.__name(formatMoney, "formatMoney");
17
+ chunkXHPRD45G_cjs.__name(formatMoney, "formatMoney");
18
18
  function formatDate(dateStr) {
19
19
  return new Date(dateStr).toLocaleDateString("en-IN", {
20
20
  year: "numeric",
@@ -22,7 +22,7 @@ function renderOrderTrackingPage(order) {
22
22
  day: "numeric"
23
23
  });
24
24
  }
25
- chunkUSNT2KNT_cjs.__name(formatDate, "formatDate");
25
+ chunkXHPRD45G_cjs.__name(formatDate, "formatDate");
26
26
  const statusConfig = {
27
27
  pending: {
28
28
  label: "Order Placed",
@@ -423,6 +423,6 @@ function renderOrderTrackingPage(order) {
423
423
  </body>
424
424
  </html>`;
425
425
  }
426
- chunkUSNT2KNT_cjs.__name(renderOrderTrackingPage, "renderOrderTrackingPage");
426
+ chunkXHPRD45G_cjs.__name(renderOrderTrackingPage, "renderOrderTrackingPage");
427
427
 
428
428
  exports.renderOrderTrackingPage = renderOrderTrackingPage;
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.67" ;
898
+ CMS_VERSION = "1.0.69" ;
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", {
@@ -27117,6 +27220,10 @@ function OrderPlacementPage({ editOrderId }) {
27117
27220
  sonner.toast.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
27118
27221
  return;
27119
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
+ }
27120
27227
  if (lines.length === 0) {
27121
27228
  sonner.toast.error("Add at least one product to the cart");
27122
27229
  return;
@@ -27348,7 +27455,8 @@ function OrderPlacementPage({ editOrderId }) {
27348
27455
  id: "c-phone",
27349
27456
  value: contactPhone,
27350
27457
  onChange: /* @__PURE__ */ __name((e) => setContactPhone(e.target.value), "onChange"),
27351
- placeholder: "phone number"
27458
+ placeholder: "phone number",
27459
+ required: contactId == null && !placeForSomeoneElse
27352
27460
  }))), /* @__PURE__ */ React.createElement("div", {
27353
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"
27354
27462
  }, /* @__PURE__ */ React.createElement(Checkbox, {
@@ -27424,6 +27532,7 @@ function OrderPlacementPage({ editOrderId }) {
27424
27532
  value: subContactPhone,
27425
27533
  onChange: /* @__PURE__ */ __name((e) => setSubContactPhone(e.target.value), "onChange"),
27426
27534
  placeholder: "phone number",
27535
+ required: placeForSomeoneElse && subContactId == null,
27427
27536
  readOnly: subContactId != null,
27428
27537
  className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
27429
27538
  })))), /* @__PURE__ */ React.createElement("div", {
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.67" ;
864
+ CMS_VERSION = "1.0.69" ;
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", {
@@ -27083,6 +27186,10 @@ function OrderPlacementPage({ editOrderId }) {
27083
27186
  toast.error(placeForSomeoneElse ? "Enter the contact's email address" : "Select a customer or enter an email address");
27084
27187
  return;
27085
27188
  }
27189
+ if (!effectivePhone) {
27190
+ toast.error(placeForSomeoneElse ? "Enter the recipient's phone number" : "Please enter the customer's phone number");
27191
+ return;
27192
+ }
27086
27193
  if (lines.length === 0) {
27087
27194
  toast.error("Add at least one product to the cart");
27088
27195
  return;
@@ -27314,7 +27421,8 @@ function OrderPlacementPage({ editOrderId }) {
27314
27421
  id: "c-phone",
27315
27422
  value: contactPhone,
27316
27423
  onChange: /* @__PURE__ */ __name((e) => setContactPhone(e.target.value), "onChange"),
27317
- placeholder: "phone number"
27424
+ placeholder: "phone number",
27425
+ required: contactId == null && !placeForSomeoneElse
27318
27426
  }))), /* @__PURE__ */ React.createElement("div", {
27319
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"
27320
27428
  }, /* @__PURE__ */ React.createElement(Checkbox, {
@@ -27390,6 +27498,7 @@ function OrderPlacementPage({ editOrderId }) {
27390
27498
  value: subContactPhone,
27391
27499
  onChange: /* @__PURE__ */ __name((e) => setSubContactPhone(e.target.value), "onChange"),
27392
27500
  placeholder: "phone number",
27501
+ required: placeForSomeoneElse && subContactId == null,
27393
27502
  readOnly: subContactId != null,
27394
27503
  className: subContactId != null ? "bg-gray-100 cursor-not-allowed" : ""
27395
27504
  })))), /* @__PURE__ */ React.createElement("div", {