@infuro/cms-core 1.0.35 → 1.0.38

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 (69) hide show
  1. package/dist/admin.cjs +1222 -1024
  2. package/dist/admin.d.cts +6 -0
  3. package/dist/admin.d.ts +6 -0
  4. package/dist/admin.js +1224 -1026
  5. package/dist/api.cjs +40 -39
  6. package/dist/api.js +8 -7
  7. package/dist/auth.cjs +51 -51
  8. package/dist/auth.d.cts +3 -3
  9. package/dist/auth.d.ts +3 -3
  10. package/dist/auth.js +3 -3
  11. package/dist/chunk-22FFHLTO.cjs +2356 -0
  12. package/dist/{chunk-CNTSLED2.cjs → chunk-E6WVP7BK.cjs} +75 -14
  13. package/dist/chunk-HCIRL37O.js +21 -0
  14. package/dist/chunk-HT5DI3XW.cjs +82 -0
  15. package/dist/{chunk-EF2JBPDM.js → chunk-KFFB6EMZ.js} +9 -0
  16. package/dist/chunk-NNQBWDCI.js +2325 -0
  17. package/dist/{chunk-TIAEXJLI.cjs → chunk-OIGCAGH7.cjs} +7 -7
  18. package/dist/{chunk-4TRPKBKO.js → chunk-P7QCLE5W.js} +52 -24
  19. package/dist/{chunk-2XE4X74C.js → chunk-PYUXVU75.js} +7801 -6871
  20. package/dist/{chunk-EQPITOP6.js → chunk-SBRBR3VO.js} +70 -9
  21. package/dist/{chunk-N44BJZ4C.cjs → chunk-SPQFNIYJ.cjs} +9 -0
  22. package/dist/chunk-UCKN4BBY.cjs +24 -0
  23. package/dist/{chunk-6KPQWRFW.js → chunk-UXMDSNIG.js} +1 -1
  24. package/dist/{chunk-BGJAV67S.cjs → chunk-VJDUKAJ3.cjs} +8207 -7261
  25. package/dist/{chunk-3KPNTQBV.cjs → chunk-WMXPKKXU.cjs} +52 -23
  26. package/dist/chunk-X47PBV4I.js +79 -0
  27. package/dist/cli.cjs +4 -2
  28. package/dist/cli.js +4 -2
  29. package/dist/emit-order-notification-trigger-D2N3KFHL.cjs +16 -0
  30. package/dist/emit-order-notification-trigger-IVLWKKJL.js +3 -0
  31. package/dist/{event-order-defaults-DUGDVGJI.cjs → event-order-defaults-EMWBIGL3.cjs} +9 -9
  32. package/dist/{event-order-defaults-6E543227.js → event-order-defaults-SDRNAZHC.js} +1 -1
  33. package/dist/index.cjs +805 -1059
  34. package/dist/index.d.cts +834 -728
  35. package/dist/index.d.ts +834 -728
  36. package/dist/index.js +385 -724
  37. package/dist/migrations/1775500000000-RssFeedsAndArticles.ts +0 -1
  38. package/dist/migrations/1775700000000-JobSchedules.ts +0 -1
  39. package/dist/migrations/1781220000000-AddWhatsappTriggerBindings.ts +23 -0
  40. package/dist/migrations/1781230000000-AddOrderNotificationTriggers.ts +46 -0
  41. package/dist/migrations/1781240000000-DropEventOrderNotificationColumns.ts +29 -0
  42. package/dist/migrations/1781250000000-RemoveOrderRefundedTrigger.ts +36 -0
  43. package/dist/migrations/1781260000000-RenameWhatsappTriggerBindingsToOrderNotificationBindings.ts +92 -0
  44. package/dist/migrations/1781270000000-ComboVendorId.ts +58 -0
  45. package/dist/order-notification-dispatcher-RU7BTGGX.cjs +18 -0
  46. package/dist/order-notification-dispatcher-XWIJYDGA.js +5 -0
  47. package/dist/{rbac-debug-db-D7ME7QUY.cjs → rbac-debug-db-KHG4FJC3.cjs} +2 -2
  48. package/dist/{rbac-debug-db-MTCTVNNM.js → rbac-debug-db-QWHOENBR.js} +1 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-46GKADYE.cjs +0 -84
  51. package/dist/chunk-7YIBMQDR.cjs +0 -86
  52. package/dist/chunk-J7XHLOLO.js +0 -830
  53. package/dist/chunk-JBRR5UYL.js +0 -87
  54. package/dist/chunk-JHF4YYRC.cjs +0 -188
  55. package/dist/chunk-PAMVINEX.cjs +0 -577
  56. package/dist/chunk-QM733NUK.js +0 -186
  57. package/dist/chunk-R73BKDRO.cjs +0 -90
  58. package/dist/chunk-TFUOHI37.cjs +0 -839
  59. package/dist/chunk-XDSNZUW7.js +0 -564
  60. package/dist/chunk-ZQ4X6OAU.js +0 -82
  61. package/dist/chunk-ZSVCP6N3.js +0 -83
  62. package/dist/email-FKR4FXFI.js +0 -5
  63. package/dist/email-KVKVPNCL.cjs +0 -58
  64. package/dist/event-order-notifications-5GSAOYVS.cjs +0 -27
  65. package/dist/event-order-notifications-IIIF23D5.js +0 -10
  66. package/dist/layout-36UFTHC5.cjs +0 -11
  67. package/dist/layout-AOBN26XG.js +0 -2
  68. package/dist/whatsapp-queue-3DXA4MXU.js +0 -2
  69. package/dist/whatsapp-queue-KG65MXD5.cjs +0 -15
package/dist/admin.cjs CHANGED
@@ -454,7 +454,8 @@ var init_vendor_scope = __esm({
454
454
  "vendor_customers",
455
455
  "discounts",
456
456
  "events",
457
- "refund_policies"
457
+ "refund_policies",
458
+ "combos"
458
459
  ]);
459
460
  VENDOR_STORE_RBAC_ENTITIES = /* @__PURE__ */ new Set([
460
461
  ...VENDOR_SCOPED_STORE_ENTITIES,
@@ -491,7 +492,7 @@ var init_admin_config_context = __esm({
491
492
  var CMS_VERSION;
492
493
  var init_cms_version = __esm({
493
494
  "src/lib/cms-version.ts"() {
494
- CMS_VERSION = "1.0.35" ;
495
+ CMS_VERSION = "1.0.38" ;
495
496
  }
496
497
  });
497
498
  function useCatalogCategories(enabled = true) {
@@ -601,25 +602,20 @@ function AdminSidebar({ variant = "sidebar" }) {
601
602
  const sessionUser = session?.user;
602
603
  const showVendorOnboard = canOnboardVendors(sessionUser);
603
604
  const vendorPortal = isVendorPortalUser(sessionUser);
604
- const { customNavItems, customNavSections = [], storeEnabled } = React26.useContext(exports.AdminConfigContext);
605
+ const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled } = React26.useContext(exports.AdminConfigContext);
605
606
  const showStoreNav = storeEnabled || vendorPortal;
606
607
  const showPlatformNav = !vendorPortal;
607
608
  const isDrawer = variant === "drawer";
608
609
  const { categories: catalogCategories } = useCatalogCategories(showStoreNav);
609
- const activeCategoryId = searchParams.get("categoryId")?.trim() ?? "";
610
+ searchParams.get("categoryId")?.trim() ?? "";
610
611
  const hasCustomEventsNav = customNavItems.some((item) => item.href === "/admin/events" || item.href.startsWith("/admin/events/")) || customNavSections.some((section) => section.items.some((item) => item.href === "/admin/events" || item.href.startsWith("/admin/events/")));
611
- const vendorCatalogCategories = catalogCategories.filter((category) => category.slug !== "events");
612
+ catalogCategories.filter((category) => category.slug !== "events");
612
613
  const isActive = /* @__PURE__ */ __name((path) => {
613
614
  if (path === "/admin/dashboard") {
614
615
  return pathname === path || vendorPortal && pathname === "/admin/analytics";
615
616
  }
616
617
  return pathname.startsWith(path);
617
618
  }, "isActive");
618
- const isVendorCategoryActive = /* @__PURE__ */ __name((categoryId) => {
619
- if (!pathname.startsWith("/admin/products")) return false;
620
- if (!activeCategoryId) return false;
621
- return activeCategoryId === String(categoryId);
622
- }, "isVendorCategoryActive");
623
619
  const linkActive = "bg-gray-200 text-gray-900";
624
620
  const linkInactive = "text-gray-600 hover:bg-gray-100 hover:text-gray-900";
625
621
  const iconActive = "text-gray-700";
@@ -706,30 +702,13 @@ function AdminSidebar({ variant = "sidebar" }) {
706
702
  }, /* @__PURE__ */ React.createElement(Icon2, {
707
703
  className: `h-4 w-4 mr-2 ${isActive(item.href) ? iconActive : iconInactive}`
708
704
  }), item.label));
709
- })))), vendorCatalogCategories.length > 0 && /* @__PURE__ */ React.createElement("div", {
710
- className: sectionCls8
711
- }, /* @__PURE__ */ React.createElement("h3", {
712
- className: headingCls
713
- }, "Categories"), /* @__PURE__ */ React.createElement("ul", {
714
- className: "space-y-0.5"
715
- }, vendorCatalogCategories.map((category) => {
716
- const href = vendorCategoryWorkspaceUrl(category.id);
717
- const active = isVendorCategoryActive(category.id);
718
- return /* @__PURE__ */ React.createElement("li", {
719
- key: category.id
720
- }, /* @__PURE__ */ React.createElement(Link2__default.default, {
721
- href,
722
- className: `${linkCls} ${active ? linkActive : linkInactive}`
723
- }, /* @__PURE__ */ React.createElement(LucideIcons.FolderTree, {
724
- className: `h-4 w-4 mr-2 ${active ? iconActive : iconInactive}`
725
- }), category.name));
726
- }))), showStoreNav && /* @__PURE__ */ React.createElement("div", {
705
+ })))), showStoreNav && /* @__PURE__ */ React.createElement("div", {
727
706
  className: sectionCls8
728
707
  }, /* @__PURE__ */ React.createElement("h3", {
729
708
  className: headingCls
730
709
  }, "Store"), /* @__PURE__ */ React.createElement("ul", {
731
710
  className: "space-y-0.5"
732
- }, showVendorOnboard && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
711
+ }, showVendorOnboard && multiVendorEnabled !== false && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
733
712
  href: "/admin/vendors",
734
713
  className: `${linkCls} ${isActive("/admin/vendors") ? linkActive : linkInactive}`
735
714
  }, /* @__PURE__ */ React.createElement(LucideIcons.Store, {
@@ -749,12 +728,12 @@ function AdminSidebar({ variant = "sidebar" }) {
749
728
  className: `${linkCls} ${isActive("/admin/brands") ? linkActive : linkInactive}`
750
729
  }, /* @__PURE__ */ React.createElement(LucideIcons.Building2, {
751
730
  className: `h-4 w-4 mr-2 ${isActive("/admin/brands") ? iconActive : iconInactive}`
752
- }), "Brands")), !hasCustomEventsNav ? /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
731
+ }), "Brands")), !hasCustomEventsNav && eventsEnabled !== false ? /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
753
732
  href: "/admin/events",
754
733
  className: `${linkCls} ${isActive("/admin/events") ? linkActive : linkInactive}`
755
734
  }, /* @__PURE__ */ React.createElement(LucideIcons.CalendarDays, {
756
735
  className: `h-4 w-4 mr-2 ${isActive("/admin/events") ? iconActive : iconInactive}`
757
- }), "Events")) : null, !vendorPortal && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
736
+ }), "Events")) : null, /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
758
737
  href: "/admin/products",
759
738
  className: `${linkCls} ${isActive("/admin/products") ? linkActive : linkInactive}`
760
739
  }, /* @__PURE__ */ React.createElement(LucideIcons.ShoppingBag, {
@@ -1182,7 +1161,7 @@ var init_builtin_plugin_descriptors = __esm({
1182
1161
  },
1183
1162
  {
1184
1163
  name: "event_notifications",
1185
- label: "Event notifications",
1164
+ label: "Notifications",
1186
1165
  version: "1.0.0",
1187
1166
  description: "Order confirmation templates with QR code and order details for events.",
1188
1167
  enabled: true,
@@ -1197,9 +1176,7 @@ var init_builtin_plugin_descriptors = __esm({
1197
1176
  function isAuthDebugClientEnabled() {
1198
1177
  if (typeof window === "undefined") return false;
1199
1178
  const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
1200
- if (v === "1" || v === "true" || v === "yes") return true;
1201
- if (v === "0" || v === "false" || v === "no") return false;
1202
- return process.env.NODE_ENV === "development";
1179
+ return v === "1" || v === "true" || v === "yes";
1203
1180
  }
1204
1181
  function logAuthClient(message, data) {
1205
1182
  if (!isAuthDebugClientEnabled()) return;
@@ -1243,13 +1220,16 @@ function useAdminViewSettings() {
1243
1220
  }
1244
1221
  function AdminLayoutInner({ children }) {
1245
1222
  const { data: session, status } = react.useSession();
1223
+ const { multiVendorEnabled } = React26.useContext(exports.AdminConfigContext);
1246
1224
  const router = navigation.useRouter();
1247
1225
  const pathname = navigation.usePathname();
1248
1226
  const [loadingTimeout, setLoadingTimeout] = React26.useState(false);
1249
1227
  const [moreSheetOpen, setMoreSheetOpen] = React26.useState(false);
1250
1228
  const isMobile = useIsMobile();
1229
+ const vendorBlockRedirectRef = React26.useRef(false);
1251
1230
  useAdminViewSettings();
1252
1231
  const isPublicPath = PUBLIC_ADMIN_PATHS.includes(pathname);
1232
+ const isVendorOnlySession = session?.user?.isVendorPortal === true && session?.user?.isRBACAdmin !== true;
1253
1233
  React26.useEffect(() => {
1254
1234
  if (isMobile) setMoreSheetOpen(false);
1255
1235
  }, [
@@ -1276,6 +1256,7 @@ function AdminLayoutInner({ children }) {
1276
1256
  return () => clearTimeout(timeout);
1277
1257
  }
1278
1258
  if (status === "unauthenticated") {
1259
+ if (vendorBlockRedirectRef.current) return;
1279
1260
  logAuthClient("AdminLayout redirect \u2192 /admin/signin (unauthenticated)", {
1280
1261
  pathname
1281
1262
  });
@@ -1289,6 +1270,29 @@ function AdminLayoutInner({ children }) {
1289
1270
  pathname,
1290
1271
  isPublicPath
1291
1272
  ]);
1273
+ React26.useEffect(() => {
1274
+ if (isPublicPath) return;
1275
+ if (status !== "authenticated" || !session) return;
1276
+ if (!multiVendorEnabled && isVendorOnlySession) {
1277
+ vendorBlockRedirectRef.current = true;
1278
+ logAuthClient("AdminLayout: vendor session blocked (multi-vendor disabled)", {
1279
+ pathname
1280
+ });
1281
+ react.signOut({
1282
+ redirect: false
1283
+ }).then(() => {
1284
+ router.replace("/admin/signin?error=CredentialsSignin");
1285
+ });
1286
+ }
1287
+ }, [
1288
+ status,
1289
+ session,
1290
+ multiVendorEnabled,
1291
+ isVendorOnlySession,
1292
+ router,
1293
+ pathname,
1294
+ isPublicPath
1295
+ ]);
1292
1296
  if (isPublicPath) {
1293
1297
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AdminStyle, null), children);
1294
1298
  }
@@ -1313,6 +1317,9 @@ function AdminLayoutInner({ children }) {
1313
1317
  if (!session) {
1314
1318
  return null;
1315
1319
  }
1320
+ if (!multiVendorEnabled && isVendorOnlySession) {
1321
+ return null;
1322
+ }
1316
1323
  const isOrderProductEmbed = pathname?.includes("/admin/orders/product-frame") === true;
1317
1324
  if (isOrderProductEmbed) {
1318
1325
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AdminStyle, null), /* @__PURE__ */ React.createElement("div", {
@@ -1384,9 +1391,48 @@ function useStoreEnabled() {
1384
1391
  currency
1385
1392
  };
1386
1393
  }
1394
+ function parseBooleanSetting(value) {
1395
+ if (typeof value === "boolean") return value;
1396
+ if (typeof value === "number") return value !== 0;
1397
+ if (typeof value === "string") {
1398
+ const normalized = value.trim().toLowerCase();
1399
+ if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") return true;
1400
+ if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") return false;
1401
+ }
1402
+ if (value && typeof value === "object") {
1403
+ const record = value;
1404
+ const nested = parseBooleanSetting(record.value ?? record.enabled ?? record.isEnabled ?? record.active ?? record.state);
1405
+ if (nested != null) return nested;
1406
+ }
1407
+ return null;
1408
+ }
1409
+ function useMultiVendorEnabled() {
1410
+ const [multiVendorEnabled, setMultiVendorEnabled] = React26.useState(true);
1411
+ React26.useEffect(() => {
1412
+ fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
1413
+ const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
1414
+ setMultiVendorEnabled(parsed ?? true);
1415
+ }).catch(() => {
1416
+ });
1417
+ }, []);
1418
+ return multiVendorEnabled;
1419
+ }
1420
+ function useEventsEnabled() {
1421
+ const [eventsEnabled, setEventsEnabled] = React26.useState(true);
1422
+ React26.useEffect(() => {
1423
+ fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
1424
+ const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
1425
+ setEventsEnabled(parsed ?? true);
1426
+ }).catch(() => {
1427
+ });
1428
+ }, []);
1429
+ return eventsEnabled;
1430
+ }
1387
1431
  function AdminLayout({ children, customNavItems = [], customNavSections = [], customCrudConfigs = {}, categoryRelatedProductLabels = {}, renderOrderDetailFooter, theme, themeRegistry, pluginDescriptors = [] }) {
1388
1432
  const resolvedTheme = useResolvedTheme(theme, themeRegistry);
1389
1433
  const { storeEnabled, currency } = useStoreEnabled();
1434
+ const multiVendorEnabled = useMultiVendorEnabled();
1435
+ const eventsEnabled = useEventsEnabled();
1390
1436
  const mergedPluginDescriptors = React26.useMemo(() => {
1391
1437
  const seen = new Set(pluginDescriptors.map((p) => p.name));
1392
1438
  const extra = BUILTIN_PLUGIN_DESCRIPTORS.filter((p) => !seen.has(p.name));
@@ -1407,7 +1453,9 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
1407
1453
  themeRegistry,
1408
1454
  pluginDescriptors: mergedPluginDescriptors,
1409
1455
  storeEnabled,
1410
- currency
1456
+ currency,
1457
+ multiVendorEnabled,
1458
+ eventsEnabled
1411
1459
  }), [
1412
1460
  customNavItems,
1413
1461
  customNavSections,
@@ -1418,7 +1466,9 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
1418
1466
  themeRegistry,
1419
1467
  mergedPluginDescriptors,
1420
1468
  storeEnabled,
1421
- currency
1469
+ currency,
1470
+ multiVendorEnabled,
1471
+ eventsEnabled
1422
1472
  ]);
1423
1473
  return /* @__PURE__ */ React.createElement(exports.AdminConfigContext.Provider, {
1424
1474
  value: configValue
@@ -1453,6 +1503,9 @@ var init_AdminLayout = __esm({
1453
1503
  __name(AdminLayoutInner, "AdminLayoutInner");
1454
1504
  __name(useResolvedTheme, "useResolvedTheme");
1455
1505
  __name(useStoreEnabled, "useStoreEnabled");
1506
+ __name(parseBooleanSetting, "parseBooleanSetting");
1507
+ __name(useMultiVendorEnabled, "useMultiVendorEnabled");
1508
+ __name(useEventsEnabled, "useEventsEnabled");
1456
1509
  __name(AdminLayout, "AdminLayout");
1457
1510
  }
1458
1511
  });
@@ -8730,6 +8783,14 @@ var init_SignInPage = __esm({
8730
8783
  const [error, setError] = React26.useState("");
8731
8784
  const [loading, setLoading] = React26.useState(false);
8732
8785
  const { status } = react.useSession();
8786
+ const searchParams = navigation.useSearchParams();
8787
+ React26.useEffect(() => {
8788
+ if (searchParams.get("error")) {
8789
+ setError("Invalid email or password");
8790
+ }
8791
+ }, [
8792
+ searchParams
8793
+ ]);
8733
8794
  React26.useEffect(() => {
8734
8795
  logAuthClient("SignInPage session status", {
8735
8796
  status
@@ -11078,8 +11139,17 @@ var init_store_crud_configs = __esm({
11078
11139
  },
11079
11140
  {
11080
11141
  param: "eventId",
11081
- label: "Event ID",
11082
- type: "text"
11142
+ label: "Event",
11143
+ type: "select",
11144
+ options: [
11145
+ {
11146
+ value: "",
11147
+ label: "All"
11148
+ }
11149
+ ],
11150
+ relationApi: "/api/events",
11151
+ relationLabelField: "name",
11152
+ relationValueField: "id"
11083
11153
  }
11084
11154
  ],
11085
11155
  columns: [
@@ -12162,6 +12232,8 @@ function SettingsPage() {
12162
12232
  });
12163
12233
  const [themeSettingsLoading, setThemeSettingsLoading] = React26.useState(true);
12164
12234
  const [storeEnabled, setStoreEnabled] = React26.useState(false);
12235
+ const [multiVendorEnabled, setMultiVendorEnabled] = React26.useState(true);
12236
+ const [eventsEnabled, setEventsEnabled] = React26.useState(true);
12165
12237
  const [storeSettingsLoading, setStoreSettingsLoading] = React26.useState(true);
12166
12238
  const [currency, setCurrency] = React26.useState(DEFAULT_CURRENCY);
12167
12239
  const [currencies, setCurrencies] = React26.useState([]);
@@ -12219,6 +12291,14 @@ function SettingsPage() {
12219
12291
  setStoreEnabled(data.enabled === "true");
12220
12292
  setCurrency(data.currency || DEFAULT_CURRENCY);
12221
12293
  }).finally(() => setStoreSettingsLoading(false));
12294
+ fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
12295
+ setMultiVendorEnabled(data.enabled !== "false");
12296
+ }).catch(() => {
12297
+ });
12298
+ fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
12299
+ setEventsEnabled(data.enabled !== "false");
12300
+ }).catch(() => {
12301
+ });
12222
12302
  fetch("/api/currencies/exchange-rates").then((r) => r.ok ? r.json() : []).then((data) => {
12223
12303
  if (data.length > 0) {
12224
12304
  setExchangeRates(data.map((entry) => ({
@@ -12335,6 +12415,30 @@ function SettingsPage() {
12335
12415
  }
12336
12416
  })
12337
12417
  });
12418
+ await fetch("/api/settings/multi_vendor", {
12419
+ method: "PUT",
12420
+ headers: {
12421
+ "Content-Type": "application/json"
12422
+ },
12423
+ body: JSON.stringify({
12424
+ enabled: {
12425
+ value: multiVendorEnabled ? "true" : "false",
12426
+ type: "public"
12427
+ }
12428
+ })
12429
+ });
12430
+ await fetch("/api/settings/events", {
12431
+ method: "PUT",
12432
+ headers: {
12433
+ "Content-Type": "application/json"
12434
+ },
12435
+ body: JSON.stringify({
12436
+ enabled: {
12437
+ value: eventsEnabled ? "true" : "false",
12438
+ type: "public"
12439
+ }
12440
+ })
12441
+ });
12338
12442
  sonner.toast.success("Store settings saved");
12339
12443
  window.location.reload();
12340
12444
  } catch {
@@ -12594,7 +12698,25 @@ function SettingsPage() {
12594
12698
  className: "text-sm font-medium text-gray-700"
12595
12699
  }, "Enable Store"), /* @__PURE__ */ React.createElement("p", {
12596
12700
  className: "text-xs text-gray-500"
12597
- }, "Shows Store section in sidebar with Products, Orders, Payments, etc.")))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
12701
+ }, "Shows Store section in sidebar with Products, Orders, Payments, etc.")))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
12702
+ className: "mt-4 flex items-center gap-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
12703
+ }, /* @__PURE__ */ React.createElement(Switch, {
12704
+ checked: multiVendorEnabled,
12705
+ onCheckedChange: setMultiVendorEnabled
12706
+ }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
12707
+ className: "text-sm font-medium text-gray-700"
12708
+ }, "Multi Vendor Support"), /* @__PURE__ */ React.createElement("p", {
12709
+ className: "text-xs text-gray-500"
12710
+ }, "Enable vendor portals, vendor logins, and vendor-scoped store data. Disabling this blocks vendor-only accounts from signing in."))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
12711
+ className: "mt-4 flex items-center gap-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
12712
+ }, /* @__PURE__ */ React.createElement(Switch, {
12713
+ checked: eventsEnabled,
12714
+ onCheckedChange: setEventsEnabled
12715
+ }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
12716
+ className: "text-sm font-medium text-gray-700"
12717
+ }, "Events"), /* @__PURE__ */ React.createElement("p", {
12718
+ className: "text-xs text-gray-500"
12719
+ }, "Enable event management. Disabling this hides the Events tab and blocks all event-related APIs."))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
12598
12720
  className: "flex items-center justify-between mb-1"
12599
12721
  }, /* @__PURE__ */ React.createElement("label", {
12600
12722
  className: "block text-sm font-semibold text-gray-700"
@@ -14182,236 +14304,774 @@ var init_email_recipients = __esm({
14182
14304
  __name(serializeEmailRecipients, "serializeEmailRecipients");
14183
14305
  }
14184
14306
  });
14185
-
14186
- // src/message-templates/event-order-defaults.ts
14187
- var EVENT_ORDER_WHATSAPP_PARAM_KEYS, EVENT_ORDER_TEMPLATE_VARIABLE_HINTS;
14188
- var init_event_order_defaults = __esm({
14189
- "src/message-templates/event-order-defaults.ts"() {
14190
- EVENT_ORDER_WHATSAPP_PARAM_KEYS = [
14191
- "customerName",
14192
- "eventName",
14307
+ function getEmailTriggerDefaults(triggerKey) {
14308
+ return EMAIL_TRIGGER_DEFAULTS[triggerKey] ?? {
14309
+ subject: "",
14310
+ body: "",
14311
+ subjectPlaceholder: "e.g. Order update for {{orderNumber}}",
14312
+ bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been updated."
14313
+ };
14314
+ }
14315
+ async function jsonFetch(url, init) {
14316
+ const res = await fetch(url, {
14317
+ credentials: "include",
14318
+ ...init
14319
+ });
14320
+ const data = await res.json().catch(() => ({}));
14321
+ if (!res.ok) {
14322
+ throw new Error(data?.error || `Request failed (${res.status})`);
14323
+ }
14324
+ return data;
14325
+ }
14326
+ function useOrderNotificationTriggerBindings(channel) {
14327
+ const [triggers, setTriggers] = React26.useState([]);
14328
+ const [bindings, setBindings] = React26.useState([]);
14329
+ const [loading, setLoading] = React26.useState(true);
14330
+ const load = React26.useCallback(async () => {
14331
+ setLoading(true);
14332
+ try {
14333
+ const [triggersRes, bindingsRes] = await Promise.all([
14334
+ jsonFetch("/api/order_notification_triggers?limit=100&sortField=sortOrder&sortOrder=asc"),
14335
+ // Bindings for all channels are fetched and filtered client-side rather
14336
+ // than relying on server-side ?channel= filtering, since that's not
14337
+ // confirmed to be supported by the generic CRUD layer.
14338
+ jsonFetch("/api/order_notification_bindings?limit=200")
14339
+ ]);
14340
+ setTriggers((triggersRes.data ?? []).filter((t) => t.enabled));
14341
+ setBindings((bindingsRes.data ?? []).filter((b) => b.channel === channel));
14342
+ } catch (e) {
14343
+ sonner.toast.error(e instanceof Error ? e.message : "Failed to load trigger bindings");
14344
+ } finally {
14345
+ setLoading(false);
14346
+ }
14347
+ }, [
14348
+ channel
14349
+ ]);
14350
+ React26.useEffect(() => {
14351
+ void load();
14352
+ }, [
14353
+ load
14354
+ ]);
14355
+ const rebind = React26.useCallback(async (triggerKey, messageTemplateId, templateLabel) => {
14356
+ const existing = bindings.find((b) => b.triggerKey === triggerKey);
14357
+ try {
14358
+ if (existing) {
14359
+ const updated = await jsonFetch(`/api/order_notification_bindings/${existing.id}`, {
14360
+ method: "PUT",
14361
+ headers: {
14362
+ "Content-Type": "application/json"
14363
+ },
14364
+ body: JSON.stringify({
14365
+ messageTemplateId
14366
+ })
14367
+ });
14368
+ setBindings((prev) => prev.map((b) => b.id === updated.id ? updated : b));
14369
+ } else {
14370
+ const created = await jsonFetch("/api/order_notification_bindings", {
14371
+ method: "POST",
14372
+ headers: {
14373
+ "Content-Type": "application/json"
14374
+ },
14375
+ body: JSON.stringify({
14376
+ triggerKey,
14377
+ channel,
14378
+ messageTemplateId,
14379
+ enabled: true
14380
+ })
14381
+ });
14382
+ setBindings((prev) => [
14383
+ ...prev,
14384
+ created
14385
+ ]);
14386
+ }
14387
+ sonner.toast.success(`"${triggerKey}" bound to "${templateLabel}"`);
14388
+ return true;
14389
+ } catch (e) {
14390
+ sonner.toast.error(e instanceof Error ? e.message : "Failed to update binding");
14391
+ return false;
14392
+ }
14393
+ }, [
14394
+ bindings,
14395
+ channel
14396
+ ]);
14397
+ return {
14398
+ triggers,
14399
+ bindings,
14400
+ loading,
14401
+ reload: load,
14402
+ rebind
14403
+ };
14404
+ }
14405
+ var KNOWN_VARS, EMAIL_TRIGGER_DEFAULTS;
14406
+ var init_order_notification_bindings_shared = __esm({
14407
+ "src/admin/components/order-notification-bindings-shared.ts"() {
14408
+ "use client";
14409
+ KNOWN_VARS = [
14410
+ "orderId",
14193
14411
  "orderNumber",
14194
- "orderTotal",
14412
+ "customerName",
14413
+ "customerPhone",
14414
+ "total",
14195
14415
  "currency",
14196
- "venue",
14197
- "startDate",
14198
- "trackUrl"
14416
+ "vendorId",
14417
+ "refundAmount"
14199
14418
  ];
14200
- EVENT_ORDER_TEMPLATE_VARIABLE_HINTS = {
14201
- eventName: "Event title",
14202
- eventSlug: "Event URL slug",
14203
- venue: "Venue name",
14204
- startDate: "Formatted event start",
14205
- orderNumber: "Order number",
14206
- orderTotal: "Order total amount",
14207
- currency: "Currency code",
14208
- customerName: "Buyer name",
14209
- customerEmail: "Buyer email",
14210
- customerPhone: "Buyer phone",
14211
- productNames: "Comma-separated ticket names",
14212
- trackUrl: "Public order tracking link (QR destination)",
14213
- qrImageUrl: 'QR code image URL for email (use in <img src="\u2026">)',
14214
- orderDetails: "Plain-text order summary with line items",
14215
- orderDetailsHtml: "HTML order summary block",
14216
- trackUrlWhatsApp: "Same as trackUrl \u2014 include in Meta template as last param"
14419
+ EMAIL_TRIGGER_DEFAULTS = {
14420
+ order_placed: {
14421
+ subject: "Your order {{orderNumber}} is confirmed",
14422
+ subjectPlaceholder: "e.g. Your order {{orderNumber}} is confirmed",
14423
+ body: `Hi {{customerName}},
14424
+
14425
+ Thank you for your order! Your order {{orderNumber}} for {{total}} {{currency}} has been confirmed.
14426
+
14427
+ We'll keep you updated on any changes.
14428
+
14429
+ Thank you!`,
14430
+ bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} for {{total}} {{currency}} is confirmed.\n\nThank you!"
14431
+ },
14432
+ order_cancelled: {
14433
+ subject: "Your order {{orderNumber}} has been cancelled",
14434
+ subjectPlaceholder: "e.g. Your order {{orderNumber}} has been cancelled",
14435
+ body: `Hi {{customerName}},
14436
+
14437
+ Your order {{orderNumber}} for {{total}} {{currency}} has been cancelled.
14438
+
14439
+ If a refund is due, you will receive {{refundAmount}} {{currency}} back to your original payment method.
14440
+
14441
+ If you have any questions, please contact us.
14442
+
14443
+ Thank you!`,
14444
+ bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been cancelled.\n\nIf a refund is due, it will be returned to your original payment method."
14445
+ }
14217
14446
  };
14447
+ __name(getEmailTriggerDefaults, "getEmailTriggerDefaults");
14448
+ __name(jsonFetch, "jsonFetch");
14449
+ __name(useOrderNotificationTriggerBindings, "useOrderNotificationTriggerBindings");
14218
14450
  }
14219
14451
  });
14220
- function mergeChannelUpdate(allItems, channel, updatedChannelItems) {
14221
- return [
14222
- ...allItems.filter((item) => item.channel !== channel),
14223
- ...updatedChannelItems
14224
- ];
14452
+ function varCount(t) {
14453
+ const explicit = t.providerMeta?.variableCount;
14454
+ if (typeof explicit === "number") return explicit;
14455
+ const matches = t.body.match(/\{\{\d+\}\}/g);
14456
+ return matches ? new Set(matches).size : 0;
14225
14457
  }
14226
- function EventOrderGlobalTemplates({ items, onChange, channel, settingsGroup = "notifications" }) {
14227
- const [templateVariables, setTemplateVariables] = React26.useState([]);
14228
- const copy = CHANNEL_COPY[channel];
14229
- const visibleItems = React26.useMemo(() => items.filter((item) => item.channel === channel), [
14230
- items,
14231
- channel
14458
+ function bodyExample(t) {
14459
+ const body = t.providerMeta?.components?.find((c) => c.type === "BODY");
14460
+ return body?.example?.body_text?.[0] ?? [];
14461
+ }
14462
+ function guessFromContext(context) {
14463
+ const c = context.toLowerCase();
14464
+ for (const { pattern, var: v } of CONTEXT_HINTS) {
14465
+ if (pattern.test(c)) return v;
14466
+ }
14467
+ return "";
14468
+ }
14469
+ function guessFromExampleShape(example) {
14470
+ const v = example.trim();
14471
+ if (!v) return "";
14472
+ if (/^\+?\d{10,15}$/.test(v)) return "customerPhone";
14473
+ if (/^[A-Z]{3}$/.test(v)) return "currency";
14474
+ if (/^[A-Za-z]{1,4}-?\d{2,}$/.test(v) || /^#?\d{3,}$/.test(v)) return "orderNumber";
14475
+ if (/^\d+(\.\d{1,2})?$/.test(v)) return "total";
14476
+ if (/^[A-Za-z]+(\s[A-Za-z]+)?$/.test(v) && v.length <= 30) return "customerName";
14477
+ return "";
14478
+ }
14479
+ function guessKnownVar(context, example, used) {
14480
+ const candidates = [
14481
+ guessFromContext(context),
14482
+ guessFromExampleShape(example)
14483
+ ].filter((v) => Boolean(v));
14484
+ for (const c of candidates) {
14485
+ if (!used.has(c)) return c;
14486
+ }
14487
+ return "";
14488
+ }
14489
+ function contextBeforePlaceholder(bodyText, n) {
14490
+ const marker = `{{${n}}}`;
14491
+ const idx = bodyText.indexOf(marker);
14492
+ if (idx === -1) return "";
14493
+ return bodyText.slice(Math.max(0, idx - 25), idx);
14494
+ }
14495
+ function WhatsAppTriggerBindings() {
14496
+ const { triggers, bindings, loading, reload, rebind } = useOrderNotificationTriggerBindings("whatsapp");
14497
+ const [templates, setTemplates] = React26.useState([]);
14498
+ const [templatesLoaded, setTemplatesLoaded] = React26.useState(false);
14499
+ const [syncing, setSyncing] = React26.useState(false);
14500
+ const [editingTemplateId, setEditingTemplateId] = React26.useState(null);
14501
+ const templatesById = React26.useMemo(() => {
14502
+ const m = /* @__PURE__ */ new Map();
14503
+ for (const t of templates) m.set(t.id, t);
14504
+ return m;
14505
+ }, [
14506
+ templates
14232
14507
  ]);
14233
- const displayVariables = React26.useMemo(() => {
14234
- if (channel === "email") return EMAIL_VARIABLES;
14235
- return [
14236
- ...EVENT_ORDER_WHATSAPP_PARAM_KEYS
14508
+ const loadTemplates = /* @__PURE__ */ __name(async () => {
14509
+ try {
14510
+ const res = await jsonFetch("/api/message-templates/whatsapp");
14511
+ setTemplates(res.items ?? []);
14512
+ } catch (e) {
14513
+ sonner.toast.error(e instanceof Error ? e.message : "Failed to load WhatsApp templates");
14514
+ } finally {
14515
+ setTemplatesLoaded(true);
14516
+ }
14517
+ }, "loadTemplates");
14518
+ React26.useMemo(() => {
14519
+ if (!templatesLoaded) void loadTemplates();
14520
+ }, [
14521
+ templatesLoaded
14522
+ ]);
14523
+ const handleSync = /* @__PURE__ */ __name(async () => {
14524
+ setSyncing(true);
14525
+ try {
14526
+ await jsonFetch("/api/message-templates/whatsapp/sync", {
14527
+ method: "POST"
14528
+ });
14529
+ await Promise.all([
14530
+ loadTemplates(),
14531
+ reload()
14532
+ ]);
14533
+ sonner.toast.success("Synced templates from Meta");
14534
+ } catch (e) {
14535
+ sonner.toast.error(e instanceof Error ? e.message : "Sync failed");
14536
+ } finally {
14537
+ setSyncing(false);
14538
+ }
14539
+ }, "handleSync");
14540
+ const handleRebind = /* @__PURE__ */ __name(async (triggerKey, messageTemplateId) => {
14541
+ const label = templatesById.get(messageTemplateId)?.name ?? String(messageTemplateId);
14542
+ await rebind(triggerKey, messageTemplateId, label);
14543
+ }, "handleRebind");
14544
+ const handleSaveParamOrder = /* @__PURE__ */ __name(async (templateId, paramOrder) => {
14545
+ try {
14546
+ const res = await jsonFetch(`/api/message-templates/whatsapp/${templateId}`, {
14547
+ method: "PATCH",
14548
+ headers: {
14549
+ "Content-Type": "application/json"
14550
+ },
14551
+ body: JSON.stringify({
14552
+ paramOrder
14553
+ })
14554
+ });
14555
+ setTemplates((prev) => prev.map((t) => t.id === res.item.id ? res.item : t));
14556
+ sonner.toast.success("Param order saved");
14557
+ setEditingTemplateId(null);
14558
+ } catch (e) {
14559
+ sonner.toast.error(e instanceof Error ? e.message : "Failed to save param order");
14560
+ }
14561
+ }, "handleSaveParamOrder");
14562
+ if (loading || !templatesLoaded) {
14563
+ return /* @__PURE__ */ React.createElement("div", {
14564
+ className: "flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"
14565
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
14566
+ className: "h-4 w-4 animate-spin"
14567
+ }), "Loading trigger bindings\u2026");
14568
+ }
14569
+ return /* @__PURE__ */ React.createElement("div", {
14570
+ className: "space-y-3 rounded-md border border-gray-200 dark:border-gray-600 p-3"
14571
+ }, /* @__PURE__ */ React.createElement("div", {
14572
+ className: "flex items-start justify-between gap-2"
14573
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
14574
+ className: "text-sm font-medium text-gray-900 dark:text-white"
14575
+ }, "Order trigger templates"), /* @__PURE__ */ React.createElement("p", {
14576
+ className: "text-xs text-gray-500 dark:text-gray-400 mt-1"
14577
+ }, "When a trigger fires, the matching template is sent on WhatsApp. Sync templates from Meta, then pick one for each trigger below.")), /* @__PURE__ */ React.createElement(Button, {
14578
+ type: "button",
14579
+ variant: "outline",
14580
+ size: "sm",
14581
+ className: "gap-1.5 h-8 shrink-0",
14582
+ disabled: syncing,
14583
+ onClick: /* @__PURE__ */ __name(() => void handleSync(), "onClick")
14584
+ }, syncing ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
14585
+ className: "h-3.5 w-3.5 animate-spin"
14586
+ }) : /* @__PURE__ */ React.createElement(LucideIcons.RefreshCw, {
14587
+ className: "h-3.5 w-3.5"
14588
+ }), "Sync from Meta")), /* @__PURE__ */ React.createElement("div", {
14589
+ className: "space-y-3"
14590
+ }, triggers.length === 0 ? /* @__PURE__ */ React.createElement("p", {
14591
+ className: "text-xs text-amber-600 dark:text-amber-400"
14592
+ }, "No order triggers found. Run database migrations to seed default triggers.") : null, triggers.map(({ triggerKey, label, description }) => {
14593
+ const binding = bindings.find((b) => b.triggerKey === triggerKey) ?? null;
14594
+ const template = binding?.messageTemplateId != null ? templatesById.get(binding.messageTemplateId) : void 0;
14595
+ const paramOrder = template?.providerMeta?.paramOrder ?? [];
14596
+ const missingParamOrder = template && varCount(template) > 0 && paramOrder.length === 0;
14597
+ return /* @__PURE__ */ React.createElement("div", {
14598
+ key: triggerKey,
14599
+ className: "space-y-2 border-t border-gray-100 pt-3 first:border-t-0 first:pt-0 dark:border-gray-700"
14600
+ }, /* @__PURE__ */ React.createElement("div", {
14601
+ className: "flex items-center gap-2"
14602
+ }, /* @__PURE__ */ React.createElement(LucideIcons.MessageCircle, {
14603
+ className: "h-3.5 w-3.5 text-gray-400 shrink-0"
14604
+ }), /* @__PURE__ */ React.createElement("span", {
14605
+ className: "text-sm font-medium text-gray-900 dark:text-gray-100"
14606
+ }, label), /* @__PURE__ */ React.createElement("span", {
14607
+ className: "text-[11px] font-mono text-gray-400"
14608
+ }, triggerKey)), description ? /* @__PURE__ */ React.createElement("p", {
14609
+ className: "text-[11px] text-gray-500 dark:text-gray-400"
14610
+ }, description) : null, /* @__PURE__ */ React.createElement("div", {
14611
+ className: "flex flex-wrap items-center gap-2"
14612
+ }, /* @__PURE__ */ React.createElement(Select, {
14613
+ value: binding?.messageTemplateId != null ? String(binding.messageTemplateId) : void 0,
14614
+ onValueChange: /* @__PURE__ */ __name((v) => void handleRebind(triggerKey, Number(v)), "onValueChange")
14615
+ }, /* @__PURE__ */ React.createElement(SelectTrigger, {
14616
+ className: "h-8 text-sm w-64"
14617
+ }, /* @__PURE__ */ React.createElement(SelectValue, {
14618
+ placeholder: "Select a template\u2026"
14619
+ })), /* @__PURE__ */ React.createElement(SelectContent, null, templates.map((t) => /* @__PURE__ */ React.createElement(SelectItem, {
14620
+ key: t.id,
14621
+ value: String(t.id)
14622
+ }, t.name, t.providerMeta?.status ? ` (${t.providerMeta.status})` : "")))), template ? /* @__PURE__ */ React.createElement(Button, {
14623
+ type: "button",
14624
+ variant: "ghost",
14625
+ size: "sm",
14626
+ className: "h-8 gap-1 text-xs",
14627
+ onClick: /* @__PURE__ */ __name(() => setEditingTemplateId(template.id), "onClick")
14628
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Settings2, {
14629
+ className: "h-3.5 w-3.5"
14630
+ }), paramOrder.length > 0 ? `Params: ${paramOrder.join(" \u2192 ")}` : "Set param order") : null), missingParamOrder ? /* @__PURE__ */ React.createElement("p", {
14631
+ className: "text-xs text-amber-600 dark:text-amber-400"
14632
+ }, "\u26A0 No param order set \u2014 variables may send in the wrong slots.") : null, template?.providerMeta?.language ? /* @__PURE__ */ React.createElement("p", {
14633
+ className: "text-[11px] text-gray-400"
14634
+ }, "Language: ", template.providerMeta.language) : null);
14635
+ })), editingTemplateId !== null && templatesById.get(editingTemplateId) && /* @__PURE__ */ React.createElement(ParamOrderEditor, {
14636
+ template: templatesById.get(editingTemplateId),
14637
+ onCancel: /* @__PURE__ */ __name(() => setEditingTemplateId(null), "onCancel"),
14638
+ onSave: /* @__PURE__ */ __name((order) => void handleSaveParamOrder(editingTemplateId, order), "onSave")
14639
+ }));
14640
+ }
14641
+ function ParamOrderEditor({ template, onCancel, onSave }) {
14642
+ const count = Math.max(varCount(template), template.providerMeta?.paramOrder?.length ?? 0);
14643
+ const example = bodyExample(template);
14644
+ const existing = template.providerMeta?.paramOrder ?? [];
14645
+ const bodyText = template.providerMeta?.components?.find((c) => c.type === "BODY")?.text ?? template.body;
14646
+ const initialGuesses = React26.useMemo(() => {
14647
+ const base = Array.from({
14648
+ length: count
14649
+ }, (_, i) => existing[i] ?? "");
14650
+ const used = new Set(base.filter(Boolean));
14651
+ const auto = /* @__PURE__ */ new Set();
14652
+ const withGuesses = base.map((v, i) => {
14653
+ if (v) return v;
14654
+ const context = contextBeforePlaceholder(bodyText, i + 1);
14655
+ const guess = guessKnownVar(context, example[i] ?? "", used);
14656
+ if (guess) {
14657
+ used.add(guess);
14658
+ auto.add(i);
14659
+ return guess;
14660
+ }
14661
+ return v;
14662
+ });
14663
+ return {
14664
+ values: withGuesses,
14665
+ autoFilled: auto
14666
+ };
14667
+ }, []);
14668
+ const [values, setValues] = React26.useState(initialGuesses.values);
14669
+ const [autoFilled, setAutoFilled] = React26.useState(initialGuesses.autoFilled);
14670
+ const [customIndex, setCustomIndex] = React26.useState(null);
14671
+ function setValue(i, v) {
14672
+ setValues((prev) => {
14673
+ const next = [
14674
+ ...prev
14675
+ ];
14676
+ next[i] = v;
14677
+ return next;
14678
+ });
14679
+ setAutoFilled((prev) => {
14680
+ if (!prev.has(i)) return prev;
14681
+ const next = new Set(prev);
14682
+ next.delete(i);
14683
+ return next;
14684
+ });
14685
+ }
14686
+ __name(setValue, "setValue");
14687
+ const allFilled = values.length > 0 && values.every((v) => v.trim() !== "");
14688
+ return /* @__PURE__ */ React.createElement("div", {
14689
+ className: "fixed inset-0 bg-black/30 flex items-center justify-center z-50 p-4"
14690
+ }, /* @__PURE__ */ React.createElement("div", {
14691
+ className: "bg-white dark:bg-gray-900 rounded-lg shadow-xl w-full max-w-lg p-5 space-y-4 border border-gray-200 dark:border-gray-700"
14692
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
14693
+ className: "font-semibold text-gray-900 dark:text-gray-100"
14694
+ }, template.name), /* @__PURE__ */ React.createElement("p", {
14695
+ className: "text-xs text-gray-500 dark:text-gray-400 mt-1 font-mono break-words"
14696
+ }, bodyText)), count === 0 ? /* @__PURE__ */ React.createElement("p", {
14697
+ className: "text-sm text-gray-500 dark:text-gray-400"
14698
+ }, "This template has no positional variables \u2014 nothing to configure.") : /* @__PURE__ */ React.createElement("div", {
14699
+ className: "space-y-2"
14700
+ }, autoFilled.size > 0 ? /* @__PURE__ */ React.createElement("p", {
14701
+ className: "text-xs text-gray-500 dark:text-gray-400"
14702
+ }, "We pre-filled variables we're fairly confident about, based on this template's wording and Meta's example values. Review and adjust anything that looks wrong before saving.") : null, Array.from({
14703
+ length: count
14704
+ }).map((_, i) => /* @__PURE__ */ React.createElement("div", {
14705
+ key: i,
14706
+ className: "flex items-center gap-2"
14707
+ }, /* @__PURE__ */ React.createElement("span", {
14708
+ className: "text-xs font-mono text-gray-400 w-10"
14709
+ }, `{{${i + 1}}}`), customIndex === i ? /* @__PURE__ */ React.createElement("input", {
14710
+ autoFocus: true,
14711
+ value: values[i],
14712
+ onChange: /* @__PURE__ */ __name((e) => setValue(i, e.target.value), "onChange"),
14713
+ onBlur: /* @__PURE__ */ __name(() => setCustomIndex(null), "onBlur"),
14714
+ placeholder: "custom variable name",
14715
+ className: "flex-1 h-8 border border-gray-300 dark:border-gray-600 rounded-md px-2 text-sm font-mono bg-transparent"
14716
+ }) : /* @__PURE__ */ React.createElement(Select, {
14717
+ value: KNOWN_VARS.includes(values[i]) ? values[i] : values[i] ? "__custom__" : void 0,
14718
+ onValueChange: /* @__PURE__ */ __name((v) => {
14719
+ if (v === "__custom__") {
14720
+ setValue(i, "");
14721
+ setCustomIndex(i);
14722
+ } else {
14723
+ setValue(i, v);
14724
+ }
14725
+ }, "onValueChange")
14726
+ }, /* @__PURE__ */ React.createElement(SelectTrigger, {
14727
+ className: "flex-1 h-8 text-sm"
14728
+ }, /* @__PURE__ */ React.createElement(SelectValue, {
14729
+ placeholder: "Select variable\u2026"
14730
+ })), /* @__PURE__ */ React.createElement(SelectContent, null, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement(SelectItem, {
14731
+ key: v,
14732
+ value: v
14733
+ }, v)), /* @__PURE__ */ React.createElement(SelectItem, {
14734
+ value: "__custom__"
14735
+ }, "Custom\u2026"))), autoFilled.has(i) ? /* @__PURE__ */ React.createElement("span", {
14736
+ className: "text-[10px] font-medium text-emerald-600 dark:text-emerald-400 shrink-0"
14737
+ }, "auto") : null, example[i] ? /* @__PURE__ */ React.createElement("span", {
14738
+ className: "text-xs text-gray-400 w-24 truncate shrink-0",
14739
+ title: example[i]
14740
+ }, "e.g. ", example[i]) : null))), /* @__PURE__ */ React.createElement("div", {
14741
+ className: "flex justify-end gap-2 pt-2"
14742
+ }, /* @__PURE__ */ React.createElement(Button, {
14743
+ type: "button",
14744
+ variant: "outline",
14745
+ size: "sm",
14746
+ onClick: onCancel
14747
+ }, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
14748
+ type: "button",
14749
+ size: "sm",
14750
+ disabled: count > 0 && !allFilled,
14751
+ onClick: /* @__PURE__ */ __name(() => onSave(values), "onClick")
14752
+ }, "Save"))));
14753
+ }
14754
+ var CONTEXT_HINTS;
14755
+ var init_whatsappTriggerBindingsPage = __esm({
14756
+ "src/admin/pages/whatsappTriggerBindingsPage.tsx"() {
14757
+ "use client";
14758
+ init_button();
14759
+ init_select();
14760
+ init_order_notification_bindings_shared();
14761
+ __name(varCount, "varCount");
14762
+ __name(bodyExample, "bodyExample");
14763
+ CONTEXT_HINTS = [
14764
+ {
14765
+ pattern: /refund/,
14766
+ var: "refundAmount"
14767
+ },
14768
+ {
14769
+ pattern: /(order\s*(no\.?|number|#|id))/,
14770
+ var: "orderNumber"
14771
+ },
14772
+ {
14773
+ pattern: /\border\b/,
14774
+ var: "orderNumber"
14775
+ },
14776
+ {
14777
+ pattern: /(phone|mobile|contact\s*number)/,
14778
+ var: "customerPhone"
14779
+ },
14780
+ {
14781
+ pattern: /(vendor|seller|store)/,
14782
+ var: "vendorId"
14783
+ },
14784
+ {
14785
+ pattern: /currency/,
14786
+ var: "currency"
14787
+ },
14788
+ {
14789
+ pattern: /(total|amount|price|pay(?:ment)?)/,
14790
+ var: "total"
14791
+ },
14792
+ {
14793
+ pattern: /(hi|hello|dear|name|customer)/,
14794
+ var: "customerName"
14795
+ }
14237
14796
  ];
14797
+ __name(guessFromContext, "guessFromContext");
14798
+ __name(guessFromExampleShape, "guessFromExampleShape");
14799
+ __name(guessKnownVar, "guessKnownVar");
14800
+ __name(contextBeforePlaceholder, "contextBeforePlaceholder");
14801
+ __name(WhatsAppTriggerBindings, "WhatsAppTriggerBindings");
14802
+ __name(ParamOrderEditor, "ParamOrderEditor");
14803
+ }
14804
+ });
14805
+ function EmailTriggerBindings() {
14806
+ const { triggers, bindings, loading, rebind } = useOrderNotificationTriggerBindings("email");
14807
+ const [templates, setTemplates] = React26.useState([]);
14808
+ const [templatesLoaded, setTemplatesLoaded] = React26.useState(false);
14809
+ const templatesById = React26.useMemo(() => {
14810
+ const m = /* @__PURE__ */ new Map();
14811
+ for (const t of templates) m.set(t.id, t);
14812
+ return m;
14238
14813
  }, [
14239
- channel
14814
+ templates
14240
14815
  ]);
14241
14816
  React26.useEffect(() => {
14242
- fetch("/api/message-templates/event-order").then((r) => r.ok ? r.json() : null).then((data) => {
14243
- if (data?.templateVariables) setTemplateVariables(data.templateVariables);
14244
- }).catch(() => void 0);
14817
+ let cancelled = false;
14818
+ (async () => {
14819
+ try {
14820
+ const res = await jsonFetch("/api/message-templates/email");
14821
+ if (!cancelled) setTemplates(res.items ?? []);
14822
+ } catch (e) {
14823
+ if (!cancelled) sonner.toast.error(e instanceof Error ? e.message : "Failed to load email templates");
14824
+ } finally {
14825
+ if (!cancelled) setTemplatesLoaded(true);
14826
+ }
14827
+ })();
14828
+ return () => {
14829
+ cancelled = true;
14830
+ };
14245
14831
  }, []);
14246
- const patchVisible = /* @__PURE__ */ __name((nextVisible) => {
14247
- onChange(mergeChannelUpdate(items, channel, nextVisible));
14248
- }, "patchVisible");
14249
- if (!visibleItems.length) return null;
14832
+ const handleTemplateSaved = /* @__PURE__ */ __name((template) => {
14833
+ setTemplates((prev) => {
14834
+ const exists = prev.some((t) => t.id === template.id);
14835
+ return exists ? prev.map((t) => t.id === template.id ? template : t) : [
14836
+ ...prev,
14837
+ template
14838
+ ].sort((a, b) => a.name.localeCompare(b.name));
14839
+ });
14840
+ }, "handleTemplateSaved");
14841
+ if (loading || !templatesLoaded) {
14842
+ return /* @__PURE__ */ React.createElement("div", {
14843
+ className: "flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"
14844
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
14845
+ className: "h-4 w-4 animate-spin"
14846
+ }), "Loading trigger bindings\u2026");
14847
+ }
14250
14848
  return /* @__PURE__ */ React.createElement("div", {
14251
14849
  className: "space-y-3 rounded-md border border-gray-200 dark:border-gray-600 p-3"
14252
14850
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
14253
14851
  className: "text-sm font-medium text-gray-900 dark:text-white"
14254
- }, copy.title), /* @__PURE__ */ React.createElement("p", {
14852
+ }, "Order trigger emails"), /* @__PURE__ */ React.createElement("p", {
14255
14853
  className: "text-xs text-gray-500 dark:text-gray-400 mt-1"
14256
- }, copy.description)), /* @__PURE__ */ React.createElement("div", {
14257
- className: "rounded-md bg-gray-50 dark:bg-gray-800/50 p-2"
14258
- }, /* @__PURE__ */ React.createElement("p", {
14259
- className: "text-[11px] font-medium text-gray-600 dark:text-gray-400 mb-1"
14260
- }, "Variables"), /* @__PURE__ */ React.createElement("div", {
14261
- className: "flex flex-wrap gap-1"
14262
- }, (displayVariables.length ? displayVariables : templateVariables).map((v) => /* @__PURE__ */ React.createElement("span", {
14263
- key: v,
14264
- className: "inline-flex rounded border border-gray-200 bg-white px-1.5 py-0.5 font-mono text-[10px] text-gray-700 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-300",
14265
- title: EVENT_ORDER_TEMPLATE_VARIABLE_HINTS[v] ?? v
14266
- }, `{{${v}}}`)))), visibleItems.map((t) => /* @__PURE__ */ React.createElement("div", {
14267
- key: t.channel,
14268
- className: "space-y-3 border-t border-gray-100 pt-3 dark:border-gray-700"
14854
+ }, "Write the subject and body for each trigger below. Use", " ", /* @__PURE__ */ React.createElement("code", {
14855
+ className: "text-[11px]"
14856
+ }, "{{variable}}"), " tokens \u2014 click a variable chip to insert it at your cursor.")), /* @__PURE__ */ React.createElement("div", {
14857
+ className: "space-y-4"
14858
+ }, triggers.length === 0 ? /* @__PURE__ */ React.createElement("p", {
14859
+ className: "text-xs text-amber-600 dark:text-amber-400"
14860
+ }, "No order triggers found. Run database migrations to seed default triggers.") : null, triggers.map(({ triggerKey, label, description }) => {
14861
+ const binding = bindings.find((b) => b.triggerKey === triggerKey) ?? null;
14862
+ const template = binding?.messageTemplateId != null ? templatesById.get(binding.messageTemplateId) : void 0;
14863
+ return /* @__PURE__ */ React.createElement(TriggerEmailEditor, {
14864
+ key: triggerKey,
14865
+ triggerKey,
14866
+ label,
14867
+ description,
14868
+ template,
14869
+ onSaved: handleTemplateSaved,
14870
+ onBind: /* @__PURE__ */ __name((templateId, templateLabel) => rebind(triggerKey, templateId, templateLabel), "onBind")
14871
+ });
14872
+ })));
14873
+ }
14874
+ function TriggerEmailEditor({ triggerKey, label, description, template, onSaved, onBind }) {
14875
+ const defaults = React26.useMemo(() => getEmailTriggerDefaults(triggerKey), [
14876
+ triggerKey
14877
+ ]);
14878
+ const [subject, setSubject] = React26.useState(() => template?.subject ?? defaults.subject);
14879
+ const [body, setBody] = React26.useState(() => template?.body ?? defaults.body);
14880
+ const [saving, setSaving] = React26.useState(false);
14881
+ const [focusedField, setFocusedField] = React26.useState("body");
14882
+ const subjectRef = React26.useRef(null);
14883
+ const bodyRef = React26.useRef(null);
14884
+ React26.useEffect(() => {
14885
+ if (template) {
14886
+ setSubject(template.subject ?? "");
14887
+ setBody(template.body ?? "");
14888
+ } else {
14889
+ setSubject(defaults.subject);
14890
+ setBody(defaults.body);
14891
+ }
14892
+ }, [
14893
+ template,
14894
+ defaults.subject,
14895
+ defaults.body
14896
+ ]);
14897
+ const savedSubject = template?.subject ?? defaults.subject;
14898
+ const savedBody = template?.body ?? defaults.body;
14899
+ const isDirty = subject !== savedSubject || body !== savedBody;
14900
+ function insertVariable(v) {
14901
+ const token = `{{${v}}}`;
14902
+ if (focusedField === "subject") {
14903
+ const el = subjectRef.current;
14904
+ const start = el?.selectionStart ?? subject.length;
14905
+ const end = el?.selectionEnd ?? subject.length;
14906
+ const next = subject.slice(0, start) + token + subject.slice(end);
14907
+ setSubject(next);
14908
+ requestAnimationFrame(() => {
14909
+ el?.focus();
14910
+ el?.setSelectionRange(start + token.length, start + token.length);
14911
+ });
14912
+ } else {
14913
+ const el = bodyRef.current;
14914
+ const start = el?.selectionStart ?? body.length;
14915
+ const end = el?.selectionEnd ?? body.length;
14916
+ const next = body.slice(0, start) + token + body.slice(end);
14917
+ setBody(next);
14918
+ requestAnimationFrame(() => {
14919
+ el?.focus();
14920
+ el?.setSelectionRange(start + token.length, start + token.length);
14921
+ });
14922
+ }
14923
+ }
14924
+ __name(insertVariable, "insertVariable");
14925
+ const canSave = body.trim() !== "";
14926
+ const handleSave = /* @__PURE__ */ __name(async () => {
14927
+ if (!canSave) return;
14928
+ setSaving(true);
14929
+ try {
14930
+ const templateName = template?.name ?? `${label} email`;
14931
+ let saved;
14932
+ if (template) {
14933
+ const res = await jsonFetch(`/api/message-templates/email/${template.id}`, {
14934
+ method: "PATCH",
14935
+ headers: {
14936
+ "Content-Type": "application/json"
14937
+ },
14938
+ body: JSON.stringify({
14939
+ name: templateName,
14940
+ subject,
14941
+ body
14942
+ })
14943
+ });
14944
+ saved = res.item;
14945
+ sonner.toast.success(`"${label}" email template saved`);
14946
+ } else {
14947
+ const res = await jsonFetch("/api/message-templates/email", {
14948
+ method: "POST",
14949
+ headers: {
14950
+ "Content-Type": "application/json"
14951
+ },
14952
+ body: JSON.stringify({
14953
+ name: templateName,
14954
+ subject,
14955
+ body
14956
+ })
14957
+ });
14958
+ saved = res.item;
14959
+ onSaved(saved);
14960
+ const bound = await onBind(saved.id, saved.name);
14961
+ if (!bound) {
14962
+ sonner.toast.success(`"${label}" email template created`);
14963
+ }
14964
+ return;
14965
+ }
14966
+ onSaved(saved);
14967
+ } catch (e) {
14968
+ sonner.toast.error(e instanceof Error ? e.message : "Failed to save template");
14969
+ } finally {
14970
+ setSaving(false);
14971
+ }
14972
+ }, "handleSave");
14973
+ return /* @__PURE__ */ React.createElement("div", {
14974
+ className: "space-y-3 border-t border-gray-100 pt-4 first:border-t-0 first:pt-0 dark:border-gray-700"
14269
14975
  }, /* @__PURE__ */ React.createElement("div", {
14270
- className: "flex flex-wrap items-center justify-between gap-2"
14976
+ className: "flex items-start justify-between gap-2"
14977
+ }, /* @__PURE__ */ React.createElement("div", {
14978
+ className: "min-w-0"
14271
14979
  }, /* @__PURE__ */ React.createElement("div", {
14272
- className: "text-sm font-medium"
14273
- }, t.name), /* @__PURE__ */ React.createElement("div", {
14274
14980
  className: "flex items-center gap-2"
14275
- }, /* @__PURE__ */ React.createElement(Label3, {
14276
- htmlFor: `${settingsGroup}-evt-${t.channel}-enabled`,
14277
- className: "text-xs text-gray-600"
14278
- }, "Enabled"), /* @__PURE__ */ React.createElement(Switch, {
14279
- id: `${settingsGroup}-evt-${t.channel}-enabled`,
14280
- checked: t.enabled,
14281
- onCheckedChange: /* @__PURE__ */ __name((v) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14282
- ...x,
14283
- enabled: v
14284
- } : x)), "onCheckedChange")
14285
- }))), t.channel === "email" ? /* @__PURE__ */ React.createElement("div", {
14981
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Mail, {
14982
+ className: "h-3.5 w-3.5 text-gray-400 shrink-0"
14983
+ }), /* @__PURE__ */ React.createElement("span", {
14984
+ className: "text-sm font-medium text-gray-900 dark:text-gray-100"
14985
+ }, label), /* @__PURE__ */ React.createElement("span", {
14986
+ className: "text-[11px] font-mono text-gray-400"
14987
+ }, triggerKey)), description ? /* @__PURE__ */ React.createElement("p", {
14988
+ className: "text-[11px] text-gray-500 dark:text-gray-400 mt-0.5 ml-5"
14989
+ }, description) : null), /* @__PURE__ */ React.createElement(Button, {
14990
+ type: "button",
14991
+ size: "sm",
14992
+ className: "h-8 gap-1.5 shrink-0",
14993
+ disabled: !canSave || saving || !isDirty && Boolean(template),
14994
+ onClick: /* @__PURE__ */ __name(() => void handleSave(), "onClick")
14995
+ }, saving ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
14996
+ className: "h-3.5 w-3.5 animate-spin"
14997
+ }) : /* @__PURE__ */ React.createElement(LucideIcons.Save, {
14998
+ className: "h-3.5 w-3.5"
14999
+ }), template ? "Save" : "Create")), !template ? /* @__PURE__ */ React.createElement("p", {
15000
+ className: "text-xs text-amber-600 dark:text-amber-400 ml-5"
15001
+ }, "No email saved for this trigger yet \u2014 review the draft below and click Create.") : null, /* @__PURE__ */ React.createElement("div", {
15002
+ className: "ml-5 space-y-3 rounded-md border border-gray-100 bg-gray-50/50 p-3 dark:border-gray-700 dark:bg-gray-800/30"
15003
+ }, /* @__PURE__ */ React.createElement("div", {
14286
15004
  className: "space-y-1"
14287
15005
  }, /* @__PURE__ */ React.createElement(Label3, {
14288
- className: "text-xs"
15006
+ className: "text-xs text-gray-600 dark:text-gray-400"
14289
15007
  }, "Subject"), /* @__PURE__ */ React.createElement(Input, {
14290
- value: t.subject,
14291
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14292
- ...x,
14293
- subject: e.target.value
14294
- } : x)), "onChange"),
14295
- className: "h-8 text-sm"
14296
- })) : null, /* @__PURE__ */ React.createElement("div", {
15008
+ ref: subjectRef,
15009
+ value: subject,
15010
+ onChange: /* @__PURE__ */ __name((e) => setSubject(e.target.value), "onChange"),
15011
+ onFocus: /* @__PURE__ */ __name(() => setFocusedField("subject"), "onFocus"),
15012
+ placeholder: defaults.subjectPlaceholder,
15013
+ className: "h-8 text-sm bg-white dark:bg-gray-900"
15014
+ })), /* @__PURE__ */ React.createElement("div", {
14297
15015
  className: "space-y-1"
14298
15016
  }, /* @__PURE__ */ React.createElement(Label3, {
14299
- className: "text-xs"
14300
- }, t.channel === "email" ? "Body (HTML)" : "Body (reference only)"), /* @__PURE__ */ React.createElement(Textarea, {
14301
- value: t.body,
14302
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14303
- ...x,
14304
- body: e.target.value
14305
- } : x)), "onChange"),
14306
- rows: t.channel === "email" ? 8 : 3,
14307
- className: "text-sm font-mono"
14308
- })), t.channel === "whatsapp" ? /* @__PURE__ */ React.createElement("div", {
14309
- className: "space-y-1"
15017
+ className: "text-xs text-gray-600 dark:text-gray-400"
15018
+ }, "Body"), /* @__PURE__ */ React.createElement(Textarea, {
15019
+ ref: bodyRef,
15020
+ value: body,
15021
+ onChange: /* @__PURE__ */ __name((e) => setBody(e.target.value), "onChange"),
15022
+ onFocus: /* @__PURE__ */ __name(() => setFocusedField("body"), "onFocus"),
15023
+ rows: 6,
15024
+ placeholder: defaults.bodyPlaceholder,
15025
+ className: "text-sm font-mono bg-white dark:bg-gray-900 resize-y min-h-[120px]"
15026
+ })), /* @__PURE__ */ React.createElement("div", {
15027
+ className: "space-y-1.5"
14310
15028
  }, /* @__PURE__ */ React.createElement(Label3, {
14311
- className: "text-xs"
14312
- }, "Meta approved template name"), /* @__PURE__ */ React.createElement(Input, {
14313
- value: t.externalTemplateRef,
14314
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14315
- ...x,
14316
- externalTemplateRef: e.target.value
14317
- } : x)), "onChange"),
14318
- placeholder: "event_order_placed",
14319
- className: "h-8 text-sm"
14320
- })) : null)));
14321
- }
14322
- async function fetchEventOrderTemplateRows() {
14323
- const res = await fetch("/api/message-templates/event-order");
14324
- if (!res.ok) return [];
14325
- const data = await res.json();
14326
- return data.items ?? [];
14327
- }
14328
- async function saveEventOrderTemplateRows(items) {
14329
- const res = await fetch("/api/message-templates/event-order", {
14330
- method: "PUT",
14331
- headers: {
14332
- "Content-Type": "application/json"
14333
- },
14334
- body: JSON.stringify({
14335
- items: items.map((t) => ({
14336
- channel: t.channel,
14337
- subject: t.subject,
14338
- body: t.body,
14339
- externalTemplateRef: t.externalTemplateRef,
14340
- enabled: t.enabled
14341
- }))
14342
- })
14343
- });
14344
- return res.ok;
14345
- }
14346
- var CHANNEL_COPY, EMAIL_VARIABLES;
14347
- var init_EventOrderGlobalTemplates = __esm({
14348
- "src/admin/components/EventOrderGlobalTemplates.tsx"() {
15029
+ className: "text-xs text-gray-500 dark:text-gray-400"
15030
+ }, "Variables \u2014 inserts into ", focusedField === "subject" ? "subject" : "body", ":"), /* @__PURE__ */ React.createElement("div", {
15031
+ className: "flex flex-wrap gap-1.5"
15032
+ }, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement("button", {
15033
+ key: v,
15034
+ type: "button",
15035
+ title: VAR_HINTS[v],
15036
+ onClick: /* @__PURE__ */ __name(() => insertVariable(v), "onClick"),
15037
+ className: "rounded border border-gray-200 bg-white px-2 py-1 font-mono text-[11px] text-gray-700 hover:border-blue-300 hover:bg-blue-50 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-300 dark:hover:border-blue-700 dark:hover:bg-blue-950/40"
15038
+ }, `{{${v}}}`))), /* @__PURE__ */ React.createElement("p", {
15039
+ className: "text-[10px] text-gray-400 dark:text-gray-500"
15040
+ }, "Hover a chip to see what each variable contains at send time."))));
15041
+ }
15042
+ var VAR_HINTS;
15043
+ var init_emailTriggersBindingsPage = __esm({
15044
+ "src/admin/pages/emailTriggersBindingsPage.tsx"() {
14349
15045
  "use client";
14350
- init_label();
15046
+ init_button();
14351
15047
  init_input();
14352
15048
  init_textarea();
14353
- init_switch();
14354
- init_event_order_defaults();
14355
- CHANNEL_COPY = {
14356
- email: {
14357
- title: "Email template",
14358
- description: "HTML email with order details and QR code. Use {{qrImageUrl}} for the QR image and {{orderDetailsHtml}} for line items."
14359
- },
14360
- whatsapp: {
14361
- title: "WhatsApp template",
14362
- description: "Must match a Meta-approved template. Body params are sent in order: " + EVENT_ORDER_WHATSAPP_PARAM_KEYS.join(", ") + "."
14363
- }
15049
+ init_label();
15050
+ init_order_notification_bindings_shared();
15051
+ VAR_HINTS = {
15052
+ orderId: "Internal order ID",
15053
+ orderNumber: "Display order number",
15054
+ customerName: "Customer full name",
15055
+ customerPhone: "Customer phone",
15056
+ total: "Order total amount",
15057
+ currency: "Currency code (e.g. INR)",
15058
+ vendorId: "Vendor / store ID",
15059
+ refundAmount: "Refund amount (refund triggers)"
14364
15060
  };
14365
- EMAIL_VARIABLES = [
14366
- "customerName",
14367
- "eventName",
14368
- "orderNumber",
14369
- "orderTotal",
14370
- "currency",
14371
- "productNames",
14372
- "orderDetailsHtml",
14373
- "venue",
14374
- "startDate",
14375
- "qrImageUrl",
14376
- "trackUrl"
14377
- ];
14378
- __name(mergeChannelUpdate, "mergeChannelUpdate");
14379
- __name(EventOrderGlobalTemplates, "EventOrderGlobalTemplates");
14380
- __name(fetchEventOrderTemplateRows, "fetchEventOrderTemplateRows");
14381
- __name(saveEventOrderTemplateRows, "saveEventOrderTemplateRows");
15061
+ __name(EmailTriggerBindings, "EmailTriggerBindings");
15062
+ __name(TriggerEmailEditor, "TriggerEmailEditor");
14382
15063
  }
14383
15064
  });
14384
15065
  function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledChange, onSaveSettings, saving }) {
14385
15066
  const [tab, setTab] = React26.useState("email");
14386
- const [templateItems, setTemplateItems] = React26.useState([]);
14387
- const [loadingTemplates, setLoadingTemplates] = React26.useState(true);
14388
- React26.useEffect(() => {
14389
- let cancelled = false;
14390
- setLoadingTemplates(true);
14391
- fetchEventOrderTemplateRows().then((rows) => {
14392
- if (!cancelled) setTemplateItems(rows);
14393
- }).finally(() => {
14394
- if (!cancelled) setLoadingTemplates(false);
14395
- });
14396
- return () => {
14397
- cancelled = true;
14398
- };
14399
- }, []);
14400
- const handleSaveAll = /* @__PURE__ */ __name(async () => {
14401
- const settingsOk = await onSaveSettings();
14402
- if (!settingsOk) {
15067
+ const handleSaveEnabled = /* @__PURE__ */ __name(async () => {
15068
+ const ok = await onSaveSettings();
15069
+ if (!ok) {
14403
15070
  sonner.toast.error("Failed to save plugin settings");
14404
15071
  return;
14405
15072
  }
14406
- if (templateItems.length > 0) {
14407
- const tplOk = await saveEventOrderTemplateRows(templateItems);
14408
- if (!tplOk) {
14409
- sonner.toast.error("Failed to save notification templates");
14410
- return;
14411
- }
14412
- }
14413
- sonner.toast.success("Event notification settings saved");
14414
- }, "handleSaveAll");
15073
+ sonner.toast.success("Settings saved");
15074
+ }, "handleSaveEnabled");
14415
15075
  return /* @__PURE__ */ React.createElement("div", {
14416
15076
  className: "space-y-5"
14417
15077
  }, /* @__PURE__ */ React.createElement("div", {
@@ -14424,19 +15084,22 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
14424
15084
  className: "space-y-2 text-sm text-gray-700 dark:text-gray-300"
14425
15085
  }, /* @__PURE__ */ React.createElement("p", {
14426
15086
  className: "font-medium text-gray-900 dark:text-white"
14427
- }, "How event notifications work"), /* @__PURE__ */ React.createElement("ol", {
15087
+ }, "Order notifications"), /* @__PURE__ */ React.createElement("ol", {
14428
15088
  className: "list-decimal pl-4 space-y-1 text-xs leading-relaxed"
14429
- }, /* @__PURE__ */ React.createElement("li", null, "Configure ", /* @__PURE__ */ React.createElement("strong", null, "global templates"), " here (email + WhatsApp)."), /* @__PURE__ */ React.createElement("li", null, "Enable notifications per event under", " ", /* @__PURE__ */ React.createElement(Link2__default.default, {
14430
- href: "/admin/events",
14431
- className: "text-blue-600 hover:underline"
14432
- }, "Events \u2192 Edit \u2192 Event settings"), "."), /* @__PURE__ */ React.createElement("li", null, "When an order is placed, customers receive order details and a QR code to track / check in.")), /* @__PURE__ */ React.createElement("p", {
15089
+ }, /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement("strong", null, "Email"), " tab: each trigger has its own subject and body \u2014 use", " ", /* @__PURE__ */ React.createElement("code", {
15090
+ className: "text-[11px]"
15091
+ }, "{{variable}}"), " tokens and click Create or Save."), /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement("strong", null, "WhatsApp"), " tab: sync Meta-approved templates, then bind a trigger to one."), /* @__PURE__ */ React.createElement("li", null, "Both tabs bind against the same trigger catalog (", /* @__PURE__ */ React.createElement("code", {
15092
+ className: "text-[11px]"
15093
+ }, "order_notification_triggers"), ") and share", " ", /* @__PURE__ */ React.createElement("code", {
15094
+ className: "text-[11px]"
15095
+ }, "order_notification_bindings"), ", keyed by trigger + channel \u2014 so the same trigger (e.g. order placed) can have its own email template and its own WhatsApp template at the same time.")), /* @__PURE__ */ React.createElement("p", {
14433
15096
  className: "text-xs text-gray-500 dark:text-gray-400"
14434
15097
  }, "Requires ", /* @__PURE__ */ React.createElement("strong", null, "Email"), " plugin (SMTP) for email and ", /* @__PURE__ */ React.createElement("strong", null, "WhatsApp"), " plugin (Meta credentials) for WhatsApp delivery.")))), /* @__PURE__ */ React.createElement("div", {
14435
15098
  className: "flex items-center justify-between gap-2"
14436
15099
  }, /* @__PURE__ */ React.createElement(Label3, {
14437
15100
  htmlFor: `${settingsGroup}-enabled`,
14438
15101
  className: "text-sm"
14439
- }, "Event notifications enabled"), /* @__PURE__ */ React.createElement(Switch, {
15102
+ }, "Order notifications enabled"), /* @__PURE__ */ React.createElement(Switch, {
14440
15103
  id: `${settingsGroup}-enabled`,
14441
15104
  checked: enabled,
14442
15105
  onCheckedChange: onEnabledChange
@@ -14456,16 +15119,9 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
14456
15119
  className: `inline-flex items-center gap-2 px-4 py-2.5 text-sm font-medium border-b-2 ${tab === "whatsapp" ? "border-gray-800 text-gray-800 dark:border-gray-200 dark:text-gray-100" : "border-transparent text-gray-500 hover:text-gray-700"}`
14457
15120
  }, /* @__PURE__ */ React.createElement(LucideIcons.MessageCircle, {
14458
15121
  className: "h-4 w-4"
14459
- }), "WhatsApp template"))), loadingTemplates ? /* @__PURE__ */ React.createElement("p", {
14460
- className: "text-sm text-gray-500"
14461
- }, "Loading templates\u2026") : /* @__PURE__ */ React.createElement(EventOrderGlobalTemplates, {
14462
- items: templateItems,
14463
- onChange: setTemplateItems,
14464
- channel: tab,
14465
- settingsGroup
14466
- }), /* @__PURE__ */ React.createElement(Button, {
15122
+ }), "WhatsApp template"))), tab === "whatsapp" ? /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null) : /* @__PURE__ */ React.createElement(EmailTriggerBindings, null), /* @__PURE__ */ React.createElement(Button, {
14467
15123
  size: "sm",
14468
- onClick: /* @__PURE__ */ __name(() => void handleSaveAll(), "onClick"),
15124
+ onClick: /* @__PURE__ */ __name(() => void handleSaveEnabled(), "onClick"),
14469
15125
  disabled: saving,
14470
15126
  className: "gap-1"
14471
15127
  }, /* @__PURE__ */ React.createElement(LucideIcons.Save, {
@@ -14478,7 +15134,8 @@ var init_EventNotificationsPluginSettings = __esm({
14478
15134
  init_button();
14479
15135
  init_label();
14480
15136
  init_switch();
14481
- init_EventOrderGlobalTemplates();
15137
+ init_whatsappTriggerBindingsPage();
15138
+ init_emailTriggersBindingsPage();
14482
15139
  __name(EventNotificationsPluginSettings, "EventNotificationsPluginSettings");
14483
15140
  }
14484
15141
  });
@@ -14858,6 +15515,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
14858
15515
  const isWhatsapp = settingsGroup === "whatsapp";
14859
15516
  const isEventNotifications = settingsGroup === "event_notifications";
14860
15517
  const isSocialMedia = settingsGroup === "social_media";
15518
+ const isMultiVendor = settingsGroup === "multi_vendor";
14861
15519
  const [enabled, setEnabled] = React26.useState(true);
14862
15520
  const [botName, setBotName] = React26.useState("");
14863
15521
  const [icon, setIcon] = React26.useState("");
@@ -14938,6 +15596,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
14938
15596
  const [smsTplItems, setSmsTplItems] = React26.useState([]);
14939
15597
  const [whatsappAccessToken, setWhatsappAccessToken] = React26.useState("");
14940
15598
  const [whatsappPhoneNumberId, setWhatsappPhoneNumberId] = React26.useState("");
15599
+ const [whatsappWabaId, setWhatsappWabaId] = React26.useState("");
14941
15600
  const [whatsappHasSavedToken, setWhatsappHasSavedToken] = React26.useState(false);
14942
15601
  const [loading, setLoading] = React26.useState(true);
14943
15602
  const [saving, setSaving] = React26.useState(false);
@@ -15204,6 +15863,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15204
15863
  setWhatsappAccessToken(savedToken);
15205
15864
  setWhatsappHasSavedToken(Boolean(savedToken));
15206
15865
  setWhatsappPhoneNumberId(String(data.phoneNumberId ?? data.WHATSAPP_PHONE_NUMBER_ID ?? "").trim());
15866
+ setWhatsappWabaId(String(data.wabaId ?? data.WHATSAPP_WABA_ID ?? "").trim());
15207
15867
  }
15208
15868
  if (isSocialMedia) {
15209
15869
  const savedLiToken = String(data.linkedin_access_token ?? "").trim();
@@ -15241,7 +15901,8 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15241
15901
  isSms,
15242
15902
  isWhatsapp,
15243
15903
  isEventNotifications,
15244
- isSocialMedia
15904
+ isSocialMedia,
15905
+ isMultiVendor
15245
15906
  ]);
15246
15907
  React26.useEffect(() => {
15247
15908
  if (!isSocialMedia || loading || linkedInOrgsPrefetchedRef.current) return;
@@ -15656,6 +16317,10 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15656
16317
  phoneNumberId: {
15657
16318
  value: whatsappPhoneNumberId.trim(),
15658
16319
  type: "public"
16320
+ },
16321
+ wabaId: {
16322
+ value: whatsappWabaId.trim(),
16323
+ type: "public"
15659
16324
  }
15660
16325
  };
15661
16326
  if (whatsappAccessToken.trim()) {
@@ -15667,6 +16332,14 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15667
16332
  }
15668
16333
  return payload2;
15669
16334
  }
16335
+ if (isMultiVendor) {
16336
+ return {
16337
+ enabled: {
16338
+ value: enabled ? "true" : "false",
16339
+ type: "public"
16340
+ }
16341
+ };
16342
+ }
15670
16343
  if (isEventNotifications) {
15671
16344
  return {
15672
16345
  enabled: {
@@ -16255,6 +16928,27 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16255
16928
  className: "h-3.5 w-3.5"
16256
16929
  }), "Save"));
16257
16930
  }
16931
+ if (isMultiVendor) {
16932
+ return /* @__PURE__ */ React.createElement("div", {
16933
+ className: "space-y-4"
16934
+ }, /* @__PURE__ */ React.createElement("div", {
16935
+ className: "flex items-center justify-between gap-2"
16936
+ }, /* @__PURE__ */ React.createElement(Label3, {
16937
+ htmlFor: `${settingsGroup}-enabled`,
16938
+ className: "text-sm"
16939
+ }, "Enabled"), /* @__PURE__ */ React.createElement(Switch, {
16940
+ id: `${settingsGroup}-enabled`,
16941
+ checked: enabled,
16942
+ onCheckedChange: setEnabled
16943
+ })), /* @__PURE__ */ React.createElement(Button, {
16944
+ size: "sm",
16945
+ onClick: handleSave,
16946
+ disabled: saving,
16947
+ className: "gap-1"
16948
+ }, /* @__PURE__ */ React.createElement(LucideIcons.Save, {
16949
+ className: "h-3.5 w-3.5"
16950
+ }), "Save"));
16951
+ }
16258
16952
  if (isEventNotifications) {
16259
16953
  return /* @__PURE__ */ React.createElement(EventNotificationsPluginSettings, {
16260
16954
  settingsGroup,
@@ -16483,6 +17177,19 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16483
17177
  className: "h-9 text-sm"
16484
17178
  })), /* @__PURE__ */ React.createElement("div", {
16485
17179
  className: "space-y-1"
17180
+ }, /* @__PURE__ */ React.createElement(Label3, {
17181
+ htmlFor: `${settingsGroup}-wabaId`,
17182
+ className: "text-sm"
17183
+ }, "WhatsApp Business Account (WABA) ID"), /* @__PURE__ */ React.createElement(Input, {
17184
+ id: `${settingsGroup}-wabaId`,
17185
+ value: whatsappWabaId,
17186
+ onChange: /* @__PURE__ */ __name((e) => setWhatsappWabaId(e.target.value), "onChange"),
17187
+ placeholder: "From Meta Business Manager \u2192 WhatsApp Accounts",
17188
+ className: "h-9 text-sm"
17189
+ }), /* @__PURE__ */ React.createElement("p", {
17190
+ className: "text-xs text-gray-500 dark:text-gray-400"
17191
+ }, "Used to list/sync approved templates for this account \u2014 distinct from the phone number ID above.")), /* @__PURE__ */ React.createElement("div", {
17192
+ className: "space-y-1"
16486
17193
  }, /* @__PURE__ */ React.createElement(Label3, {
16487
17194
  htmlFor: `${settingsGroup}-accessToken`,
16488
17195
  className: "text-sm"
@@ -16493,9 +17200,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16493
17200
  onChange: /* @__PURE__ */ __name((e) => setWhatsappAccessToken(e.target.value), "onChange"),
16494
17201
  placeholder: "Permanent or system user token",
16495
17202
  className: "h-9 text-sm"
16496
- })), /* @__PURE__ */ React.createElement("p", {
16497
- className: "text-xs text-gray-500 dark:text-gray-400"
16498
- }, "Message templates for events are configured under Plugins \u2192 Event notifications."), /* @__PURE__ */ React.createElement(Button, {
17203
+ })), /* @__PURE__ */ React.createElement(Button, {
16499
17204
  size: "sm",
16500
17205
  onClick: handleSave,
16501
17206
  disabled: saving
@@ -24173,7 +24878,7 @@ function LayoutPanelContent() {
24173
24878
  flexFill: props.flexFill ?? false
24174
24879
  };
24175
24880
  const fieldCls = "flex items-center gap-2 min-h-[28px]";
24176
- const labelCls9 = "text-[11px] text-gray-500 font-medium w-14 shrink-0";
24881
+ const labelCls8 = "text-[11px] text-gray-500 font-medium w-14 shrink-0";
24177
24882
  const inputCls9 = "h-7 text-xs flex-1 min-w-0 rounded border border-input bg-background px-2";
24178
24883
  const selectCls = "h-7 w-full text-xs rounded border border-input bg-background px-2";
24179
24884
  return /* @__PURE__ */ React26__namespace.default.createElement("div", {
@@ -24187,7 +24892,7 @@ function LayoutPanelContent() {
24187
24892
  }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
24188
24893
  className: fieldCls
24189
24894
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24190
- className: labelCls9
24895
+ className: labelCls8
24191
24896
  }, "W"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24192
24897
  value: layoutProps.width,
24193
24898
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("width", e.target.value), "onChange"),
@@ -24196,7 +24901,7 @@ function LayoutPanelContent() {
24196
24901
  })), /* @__PURE__ */ React26__namespace.default.createElement("div", {
24197
24902
  className: fieldCls
24198
24903
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24199
- className: labelCls9
24904
+ className: labelCls8
24200
24905
  }, "H"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24201
24906
  value: layoutProps.height,
24202
24907
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("height", e.target.value), "onChange"),
@@ -24211,7 +24916,7 @@ function LayoutPanelContent() {
24211
24916
  }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
24212
24917
  className: fieldCls
24213
24918
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24214
- className: labelCls9
24919
+ className: labelCls8
24215
24920
  }, "Margin"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24216
24921
  value: layoutProps.margin,
24217
24922
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("margin", e.target.value), "onChange"),
@@ -24220,7 +24925,7 @@ function LayoutPanelContent() {
24220
24925
  })), /* @__PURE__ */ React26__namespace.default.createElement("div", {
24221
24926
  className: fieldCls
24222
24927
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24223
- className: labelCls9
24928
+ className: labelCls8
24224
24929
  }, "Padding"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24225
24930
  value: layoutProps.padding,
24226
24931
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("padding", e.target.value), "onChange"),
@@ -24235,7 +24940,7 @@ function LayoutPanelContent() {
24235
24940
  }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
24236
24941
  className: fieldCls
24237
24942
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24238
- className: labelCls9
24943
+ className: labelCls8
24239
24944
  }, "Radius"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24240
24945
  value: layoutProps.borderRadius,
24241
24946
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("borderRadius", e.target.value), "onChange"),
@@ -24244,7 +24949,7 @@ function LayoutPanelContent() {
24244
24949
  })), /* @__PURE__ */ React26__namespace.default.createElement("div", {
24245
24950
  className: fieldCls
24246
24951
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24247
- className: labelCls9
24952
+ className: labelCls8
24248
24953
  }, "Shadow"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
24249
24954
  value: layoutProps.boxShadow,
24250
24955
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("boxShadow", e.target.value), "onChange"),
@@ -24259,7 +24964,7 @@ function LayoutPanelContent() {
24259
24964
  }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
24260
24965
  className: fieldCls
24261
24966
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24262
- className: labelCls9
24967
+ className: labelCls8
24263
24968
  }, "Direction"), /* @__PURE__ */ React26__namespace.default.createElement("select", {
24264
24969
  value: layoutProps.flexDirection,
24265
24970
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("flexDirection", e.target.value), "onChange"),
@@ -24275,7 +24980,7 @@ function LayoutPanelContent() {
24275
24980
  }, "Column reverse"))), /* @__PURE__ */ React26__namespace.default.createElement("div", {
24276
24981
  className: fieldCls
24277
24982
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24278
- className: labelCls9
24983
+ className: labelCls8
24279
24984
  }, "Align"), /* @__PURE__ */ React26__namespace.default.createElement("select", {
24280
24985
  value: layoutProps.alignItems,
24281
24986
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("alignItems", e.target.value), "onChange"),
@@ -24291,7 +24996,7 @@ function LayoutPanelContent() {
24291
24996
  }, "Stretch"))), /* @__PURE__ */ React26__namespace.default.createElement("div", {
24292
24997
  className: fieldCls
24293
24998
  }, /* @__PURE__ */ React26__namespace.default.createElement(Label3, {
24294
- className: labelCls9
24999
+ className: labelCls8
24295
25000
  }, "Justify"), /* @__PURE__ */ React26__namespace.default.createElement("select", {
24296
25001
  value: layoutProps.justifyContent,
24297
25002
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("justifyContent", e.target.value), "onChange"),
@@ -25569,47 +26274,6 @@ var init_ProductIncomeCalculatorDialog = __esm({
25569
26274
  });
25570
26275
 
25571
26276
  // src/lib/currency-prices.ts
25572
- function normalizeCurrencyCode(code) {
25573
- return code.trim().toUpperCase();
25574
- }
25575
- function parseCurrencyPrices(raw) {
25576
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
25577
- const out = {};
25578
- for (const [key, value] of Object.entries(raw)) {
25579
- const code = normalizeCurrencyCode(key);
25580
- if (!code) continue;
25581
- const n = Number(value);
25582
- if (Number.isFinite(n) && n >= 0) out[code] = n;
25583
- }
25584
- return out;
25585
- }
25586
- function serializeCurrencyPrices(defaultCurrency, defaultPrice, additional) {
25587
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25588
- const out = {
25589
- [base]: defaultPrice
25590
- };
25591
- for (const [code, amount] of Object.entries(additional)) {
25592
- const normalized = normalizeCurrencyCode(code);
25593
- if (!normalized || normalized === base) continue;
25594
- if (Number.isFinite(amount) && amount >= 0) out[normalized] = amount;
25595
- }
25596
- return Object.keys(out).length ? out : null;
25597
- }
25598
- function currencyPricesToForm(defaultCurrency, storedPrice, currencyPrices) {
25599
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25600
- const map = parseCurrencyPrices(currencyPrices);
25601
- const defaultFromMap = map[base];
25602
- const defaultPrice = defaultFromMap != null ? String(defaultFromMap) : storedPrice != null && Number.isFinite(Number(storedPrice)) ? String(storedPrice) : "";
25603
- const additional = {};
25604
- for (const [code, amount] of Object.entries(map)) {
25605
- if (code === base) continue;
25606
- additional[code] = String(amount);
25607
- }
25608
- return {
25609
- defaultPrice,
25610
- additional
25611
- };
25612
- }
25613
26277
  function parseDefaultProductPrice(defaultPriceRaw) {
25614
26278
  const trimmed = defaultPriceRaw.trim();
25615
26279
  if (!trimmed) return null;
@@ -25619,31 +26283,9 @@ function parseDefaultProductPrice(defaultPriceRaw) {
25619
26283
  price: Math.round(price * 100) / 100
25620
26284
  };
25621
26285
  }
25622
- function formToCurrencyPricesPayload(defaultCurrency, defaultPriceRaw, additionalForm) {
25623
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25624
- const defaultPrice = Number(defaultPriceRaw.trim());
25625
- if (!Number.isFinite(defaultPrice) || defaultPrice < 0) return null;
25626
- const additional = {};
25627
- for (const [code, raw] of Object.entries(additionalForm)) {
25628
- const trimmed = raw.trim();
25629
- if (!trimmed) continue;
25630
- const n = Number(trimmed);
25631
- if (!Number.isFinite(n) || n < 0) continue;
25632
- additional[normalizeCurrencyCode(code)] = n;
25633
- }
25634
- return {
25635
- price: defaultPrice,
25636
- currencyPrices: serializeCurrencyPrices(base, defaultPrice, additional)
25637
- };
25638
- }
25639
26286
  var init_currency_prices = __esm({
25640
26287
  "src/lib/currency-prices.ts"() {
25641
- __name(normalizeCurrencyCode, "normalizeCurrencyCode");
25642
- __name(parseCurrencyPrices, "parseCurrencyPrices");
25643
- __name(serializeCurrencyPrices, "serializeCurrencyPrices");
25644
- __name(currencyPricesToForm, "currencyPricesToForm");
25645
26288
  __name(parseDefaultProductPrice, "parseDefaultProductPrice");
25646
- __name(formToCurrencyPricesPayload, "formToCurrencyPricesPayload");
25647
26289
  }
25648
26290
  });
25649
26291
 
@@ -28860,428 +29502,6 @@ var init_EventProductsSection = __esm({
28860
29502
  __name(EventProductsSection, "EventProductsSection");
28861
29503
  }
28862
29504
  });
28863
- function VariableChip({ name, onCopy }) {
28864
- return /* @__PURE__ */ React.createElement("button", {
28865
- type: "button",
28866
- onClick: onCopy,
28867
- className: "inline-flex items-center rounded-md border border-gray-200 bg-white px-2 py-0.5 font-mono text-[11px] text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700",
28868
- title: "Click to copy"
28869
- }, `{{${name}}}`);
28870
- }
28871
- function ChannelToggle({ label, icon: Icon2, checked, onChange }) {
28872
- return /* @__PURE__ */ React.createElement("button", {
28873
- type: "button",
28874
- role: "checkbox",
28875
- "aria-checked": checked,
28876
- onClick: onChange,
28877
- className: `inline-flex items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium transition-colors ${checked ? "border-gray-800 bg-gray-900 text-white dark:border-gray-300 dark:bg-gray-100 dark:text-gray-900" : "border-gray-200 bg-white text-gray-700 hover:border-gray-300 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"}`
28878
- }, /* @__PURE__ */ React.createElement(Icon2, {
28879
- className: "h-4 w-4 shrink-0"
28880
- }), label);
28881
- }
28882
- function EventNotificationSettings({ eventId }) {
28883
- const [loading, setLoading] = React26.useState(true);
28884
- const [saving, setSaving] = React26.useState(false);
28885
- const [settings, setSettings] = React26.useState(null);
28886
- const [testEmail, setTestEmail] = React26.useState("");
28887
- const [testPhone, setTestPhone] = React26.useState("");
28888
- const [testing, setTesting] = React26.useState(null);
28889
- const [varsOpen, setVarsOpen] = React26.useState(false);
28890
- const load = React26.useCallback(async () => {
28891
- setLoading(true);
28892
- try {
28893
- const res = await fetch(`/api/events/${eventId}/notifications`);
28894
- if (!res.ok) throw new Error("Failed to load");
28895
- const data = await res.json();
28896
- setSettings(data);
28897
- } catch {
28898
- sonner.toast.error("Could not load notification settings");
28899
- } finally {
28900
- setLoading(false);
28901
- }
28902
- }, [
28903
- eventId
28904
- ]);
28905
- React26.useEffect(() => {
28906
- void load();
28907
- }, [
28908
- load
28909
- ]);
28910
- const toggleChannel = /* @__PURE__ */ __name((ch) => {
28911
- if (!settings) return;
28912
- const has = settings.channels.includes(ch);
28913
- setSettings({
28914
- ...settings,
28915
- channels: has ? settings.channels.filter((c) => c !== ch) : [
28916
- ...settings.channels,
28917
- ch
28918
- ]
28919
- });
28920
- }, "toggleChannel");
28921
- const updateTemplate = /* @__PURE__ */ __name((ch, patch) => {
28922
- if (!settings) return;
28923
- setSettings({
28924
- ...settings,
28925
- templates: {
28926
- ...settings.templates,
28927
- [ch]: {
28928
- ...settings.templates[ch],
28929
- ...patch
28930
- }
28931
- }
28932
- });
28933
- }, "updateTemplate");
28934
- const resetTemplate = /* @__PURE__ */ __name((ch) => {
28935
- if (!settings) return;
28936
- const def = settings.globalDefaults.find((d) => d.channel === ch);
28937
- if (!def) return;
28938
- setSettings({
28939
- ...settings,
28940
- templates: {
28941
- ...settings.templates,
28942
- [ch]: {
28943
- subject: def.subject ?? "",
28944
- body: def.body,
28945
- externalTemplateRef: def.externalTemplateRef ?? ""
28946
- }
28947
- }
28948
- });
28949
- sonner.toast.success(`${ch === "email" ? "Email" : "WhatsApp"} template reset to default`);
28950
- }, "resetTemplate");
28951
- const copyVariable = /* @__PURE__ */ __name(async (name) => {
28952
- try {
28953
- await navigator.clipboard.writeText(`{{${name}}}`);
28954
- sonner.toast.success(`Copied {{${name}}}`);
28955
- } catch {
28956
- sonner.toast.error("Could not copy");
28957
- }
28958
- }, "copyVariable");
28959
- const handleSave = /* @__PURE__ */ __name(async () => {
28960
- if (!settings) return;
28961
- setSaving(true);
28962
- try {
28963
- const res = await fetch(`/api/events/${eventId}/notifications`, {
28964
- method: "PUT",
28965
- headers: {
28966
- "Content-Type": "application/json"
28967
- },
28968
- body: JSON.stringify({
28969
- enabled: settings.enabled,
28970
- channels: settings.channels,
28971
- templates: settings.templates
28972
- })
28973
- });
28974
- if (!res.ok) throw new Error();
28975
- sonner.toast.success("Notification settings saved");
28976
- await load();
28977
- } catch {
28978
- sonner.toast.error("Failed to save notification settings");
28979
- } finally {
28980
- setSaving(false);
28981
- }
28982
- }, "handleSave");
28983
- const sendTest = /* @__PURE__ */ __name(async (channel) => {
28984
- setTesting(channel);
28985
- try {
28986
- const res = await fetch(`/api/events/${eventId}/notifications/test`, {
28987
- method: "POST",
28988
- headers: {
28989
- "Content-Type": "application/json"
28990
- },
28991
- body: JSON.stringify({
28992
- channel,
28993
- email: testEmail.trim() || void 0,
28994
- phone: testPhone.trim() || void 0
28995
- })
28996
- });
28997
- const data = await res.json().catch(() => ({}));
28998
- if (!res.ok) {
28999
- sonner.toast.error(data.error ?? "Test failed");
29000
- return;
29001
- }
29002
- sonner.toast.success(data.message ?? "Test notification queued");
29003
- } catch {
29004
- sonner.toast.error("Test failed");
29005
- } finally {
29006
- setTesting(null);
29007
- }
29008
- }, "sendTest");
29009
- if (loading) {
29010
- return /* @__PURE__ */ React.createElement("div", {
29011
- className: `${panelCls} flex items-center gap-2 text-sm text-gray-500`
29012
- }, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
29013
- className: "h-4 w-4 animate-spin"
29014
- }), "Loading notification settings\u2026");
29015
- }
29016
- if (!settings) return null;
29017
- const emailTpl = settings.templates.email ?? {};
29018
- const waTpl = settings.templates.whatsapp ?? {};
29019
- const emailDefault = settings.globalDefaults.find((d) => d.channel === "email");
29020
- const waDefault = settings.globalDefaults.find((d) => d.channel === "whatsapp");
29021
- return /* @__PURE__ */ React.createElement("div", {
29022
- className: "space-y-5"
29023
- }, /* @__PURE__ */ React.createElement("div", {
29024
- className: panelCls
29025
- }, /* @__PURE__ */ React.createElement("div", {
29026
- className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
29027
- }, /* @__PURE__ */ React.createElement("div", {
29028
- className: "space-y-1 min-w-0"
29029
- }, /* @__PURE__ */ React.createElement("label", {
29030
- className: "flex items-start gap-3 cursor-pointer group"
29031
- }, /* @__PURE__ */ React.createElement("input", {
29032
- type: "checkbox",
29033
- checked: settings.enabled,
29034
- onChange: /* @__PURE__ */ __name((e) => setSettings({
29035
- ...settings,
29036
- enabled: e.target.checked
29037
- }), "onChange"),
29038
- className: "mt-0.5 h-4 w-4 rounded border-gray-300"
29039
- }), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", {
29040
- className: "block text-sm font-medium text-gray-900 dark:text-gray-100"
29041
- }, "Send notifications when an order is placed"), /* @__PURE__ */ React.createElement("span", {
29042
- className: hintCls
29043
- }, "Uses global templates from Plugins \u2192 Event notifications. Requires Email and/or WhatsApp plugins for delivery."))))), settings.enabled ? /* @__PURE__ */ React.createElement("div", {
29044
- className: "mt-5 pt-5 border-t border-gray-100 dark:border-gray-700"
29045
- }, /* @__PURE__ */ React.createElement("p", {
29046
- className: labelCls5
29047
- }, "Channels"), /* @__PURE__ */ React.createElement("div", {
29048
- className: "flex flex-wrap gap-2"
29049
- }, /* @__PURE__ */ React.createElement(ChannelToggle, {
29050
- label: "Email",
29051
- icon: LucideIcons.Mail,
29052
- checked: settings.channels.includes("email"),
29053
- onChange: /* @__PURE__ */ __name(() => toggleChannel("email"), "onChange")
29054
- }), /* @__PURE__ */ React.createElement(ChannelToggle, {
29055
- label: "WhatsApp",
29056
- icon: LucideIcons.MessageCircle,
29057
- checked: settings.channels.includes("whatsapp"),
29058
- onChange: /* @__PURE__ */ __name(() => toggleChannel("whatsapp"), "onChange")
29059
- })), settings.channels.length === 0 ? /* @__PURE__ */ React.createElement("p", {
29060
- className: "mt-2 text-xs text-amber-700 dark:text-amber-400"
29061
- }, "Select at least one channel to send notifications.") : null) : null), settings.enabled && settings.channels.length > 0 ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
29062
- className: panelCls
29063
- }, /* @__PURE__ */ React.createElement("button", {
29064
- type: "button",
29065
- onClick: /* @__PURE__ */ __name(() => setVarsOpen((o) => !o), "onClick"),
29066
- className: "flex w-full items-center justify-between gap-2 text-left"
29067
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
29068
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29069
- }, "Template variables"), /* @__PURE__ */ React.createElement("p", {
29070
- className: hintCls
29071
- }, "Click a variable to copy it into your template.")), varsOpen ? /* @__PURE__ */ React.createElement(LucideIcons.ChevronUp, {
29072
- className: "h-4 w-4 shrink-0 text-gray-400"
29073
- }) : /* @__PURE__ */ React.createElement(LucideIcons.ChevronDown, {
29074
- className: "h-4 w-4 shrink-0 text-gray-400"
29075
- })), varsOpen ? /* @__PURE__ */ React.createElement("div", {
29076
- className: "mt-3 flex flex-wrap gap-1.5"
29077
- }, settings.templateVariables.map((v) => /* @__PURE__ */ React.createElement(VariableChip, {
29078
- key: v,
29079
- name: v,
29080
- onCopy: /* @__PURE__ */ __name(() => copyVariable(v), "onCopy")
29081
- }))) : null), settings.channels.includes("email") ? /* @__PURE__ */ React.createElement("div", {
29082
- className: panelCls
29083
- }, /* @__PURE__ */ React.createElement("div", {
29084
- className: "flex flex-wrap items-center justify-between gap-3 mb-4"
29085
- }, /* @__PURE__ */ React.createElement("div", {
29086
- className: "flex items-center gap-2"
29087
- }, /* @__PURE__ */ React.createElement(LucideIcons.Mail, {
29088
- className: "h-4 w-4 text-gray-500"
29089
- }), /* @__PURE__ */ React.createElement("h3", {
29090
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
29091
- }, "Email template")), /* @__PURE__ */ React.createElement(Button, {
29092
- type: "button",
29093
- variant: "outline",
29094
- size: "sm",
29095
- onClick: /* @__PURE__ */ __name(() => resetTemplate("email"), "onClick"),
29096
- className: "gap-1.5 h-8"
29097
- }, /* @__PURE__ */ React.createElement(LucideIcons.RotateCcw, {
29098
- className: "h-3.5 w-3.5"
29099
- }), "Reset to default")), /* @__PURE__ */ React.createElement("div", {
29100
- className: subPanelCls
29101
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29102
- className: labelCls5
29103
- }, "Subject"), /* @__PURE__ */ React.createElement(Input, {
29104
- value: emailTpl.subject ?? "",
29105
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("email", {
29106
- subject: e.target.value
29107
- }), "onChange"),
29108
- className: "h-9 text-sm",
29109
- placeholder: emailDefault?.subject ?? "Order confirmation for {{eventName}}"
29110
- })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29111
- className: labelCls5
29112
- }, "Body"), /* @__PURE__ */ React.createElement("p", {
29113
- className: `${hintCls} mb-2`
29114
- }, "HTML is supported. Use variables from the list above."), /* @__PURE__ */ React.createElement(Textarea, {
29115
- value: emailTpl.body ?? "",
29116
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("email", {
29117
- body: e.target.value
29118
- }), "onChange"),
29119
- rows: 8,
29120
- className: "text-sm font-mono min-h-[180px] resize-y",
29121
- placeholder: emailDefault?.body ?? ""
29122
- })))) : null, settings.channels.includes("whatsapp") ? /* @__PURE__ */ React.createElement("div", {
29123
- className: panelCls
29124
- }, /* @__PURE__ */ React.createElement("div", {
29125
- className: "flex flex-wrap items-center justify-between gap-3 mb-4"
29126
- }, /* @__PURE__ */ React.createElement("div", {
29127
- className: "flex items-center gap-2"
29128
- }, /* @__PURE__ */ React.createElement(LucideIcons.MessageCircle, {
29129
- className: "h-4 w-4 text-gray-500"
29130
- }), /* @__PURE__ */ React.createElement("h3", {
29131
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
29132
- }, "WhatsApp template")), /* @__PURE__ */ React.createElement(Button, {
29133
- type: "button",
29134
- variant: "outline",
29135
- size: "sm",
29136
- onClick: /* @__PURE__ */ __name(() => resetTemplate("whatsapp"), "onClick"),
29137
- className: "gap-1.5 h-8"
29138
- }, /* @__PURE__ */ React.createElement(LucideIcons.RotateCcw, {
29139
- className: "h-3.5 w-3.5"
29140
- }), "Reset to default")), /* @__PURE__ */ React.createElement("div", {
29141
- className: subPanelCls
29142
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29143
- className: labelCls5
29144
- }, "Meta approved template name"), /* @__PURE__ */ React.createElement(Input, {
29145
- value: waTpl.externalTemplateRef ?? "",
29146
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("whatsapp", {
29147
- externalTemplateRef: e.target.value
29148
- }), "onChange"),
29149
- placeholder: waDefault?.externalTemplateRef ?? "event_order_placed",
29150
- className: "h-9 text-sm"
29151
- }), /* @__PURE__ */ React.createElement("p", {
29152
- className: `${hintCls} mt-1.5`
29153
- }, "Must match a template approved in your Meta Business account.")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29154
- className: labelCls5
29155
- }, "Body (reference)"), /* @__PURE__ */ React.createElement("p", {
29156
- className: `${hintCls} mb-2`
29157
- }, "Used as fallback documentation; WhatsApp sends via the Meta template above."), /* @__PURE__ */ React.createElement(Textarea, {
29158
- value: waTpl.body ?? "",
29159
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("whatsapp", {
29160
- body: e.target.value
29161
- }), "onChange"),
29162
- rows: 4,
29163
- className: "text-sm min-h-[100px] resize-y",
29164
- placeholder: waDefault?.body ?? ""
29165
- })))) : null, /* @__PURE__ */ React.createElement("div", {
29166
- className: panelCls
29167
- }, /* @__PURE__ */ React.createElement("p", {
29168
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1"
29169
- }, "Send test"), /* @__PURE__ */ React.createElement("p", {
29170
- className: `${hintCls} mb-4`
29171
- }, "Queue a test notification with sample order data. Uses the templates above (save first if you changed them)."), /* @__PURE__ */ React.createElement("div", {
29172
- className: "grid gap-4 sm:grid-cols-2"
29173
- }, /* @__PURE__ */ React.createElement("div", {
29174
- className: subPanelCls
29175
- }, /* @__PURE__ */ React.createElement("div", {
29176
- className: "flex items-center gap-2 mb-3"
29177
- }, /* @__PURE__ */ React.createElement(LucideIcons.Mail, {
29178
- className: "h-4 w-4 text-gray-500"
29179
- }), /* @__PURE__ */ React.createElement("span", {
29180
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29181
- }, "Test email")), /* @__PURE__ */ React.createElement(Label3, {
29182
- className: labelCls5
29183
- }, "Recipient"), /* @__PURE__ */ React.createElement(Input, {
29184
- value: testEmail,
29185
- onChange: /* @__PURE__ */ __name((e) => setTestEmail(e.target.value), "onChange"),
29186
- type: "email",
29187
- className: "h-9 text-sm mb-3",
29188
- placeholder: "you@example.com"
29189
- }), /* @__PURE__ */ React.createElement(Button, {
29190
- type: "button",
29191
- variant: "outline",
29192
- size: "sm",
29193
- disabled: testing !== null || !settings.channels.includes("email"),
29194
- onClick: /* @__PURE__ */ __name(() => sendTest("email"), "onClick"),
29195
- className: "gap-1.5 w-full sm:w-auto"
29196
- }, testing === "email" ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
29197
- className: "h-3.5 w-3.5 animate-spin"
29198
- }) : /* @__PURE__ */ React.createElement(LucideIcons.Send, {
29199
- className: "h-3.5 w-3.5"
29200
- }), "Send test email")), /* @__PURE__ */ React.createElement("div", {
29201
- className: subPanelCls
29202
- }, /* @__PURE__ */ React.createElement("div", {
29203
- className: "flex items-center gap-2 mb-3"
29204
- }, /* @__PURE__ */ React.createElement(LucideIcons.MessageCircle, {
29205
- className: "h-4 w-4 text-gray-500"
29206
- }), /* @__PURE__ */ React.createElement("span", {
29207
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29208
- }, "Test WhatsApp")), /* @__PURE__ */ React.createElement(Label3, {
29209
- className: labelCls5
29210
- }, "Phone number"), /* @__PURE__ */ React.createElement(Input, {
29211
- value: testPhone,
29212
- onChange: /* @__PURE__ */ __name((e) => setTestPhone(e.target.value), "onChange"),
29213
- className: "h-9 text-sm mb-3",
29214
- placeholder: "+91 98765 43210"
29215
- }), /* @__PURE__ */ React.createElement(Button, {
29216
- type: "button",
29217
- variant: "outline",
29218
- size: "sm",
29219
- disabled: testing !== null || !settings.channels.includes("whatsapp"),
29220
- onClick: /* @__PURE__ */ __name(() => sendTest("whatsapp"), "onClick"),
29221
- className: "gap-1.5 w-full sm:w-auto"
29222
- }, testing === "whatsapp" ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
29223
- className: "h-3.5 w-3.5 animate-spin"
29224
- }) : /* @__PURE__ */ React.createElement(LucideIcons.Send, {
29225
- className: "h-3.5 w-3.5"
29226
- }), "Send test WhatsApp"))))) : null, /* @__PURE__ */ React.createElement("div", {
29227
- className: "flex justify-end pt-1"
29228
- }, /* @__PURE__ */ React.createElement(Button, {
29229
- type: "button",
29230
- onClick: handleSave,
29231
- disabled: saving,
29232
- className: "min-w-[160px]"
29233
- }, saving ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
29234
- className: "h-4 w-4 animate-spin mr-2"
29235
- }), "Saving\u2026") : "Save settings")));
29236
- }
29237
- function EventNotificationSummary({ eventId }) {
29238
- const [summary, setSummary] = React26.useState(null);
29239
- React26.useEffect(() => {
29240
- let cancelled = false;
29241
- fetch(`/api/events/${eventId}/notifications`).then((r) => r.ok ? r.json() : null).then((data) => {
29242
- if (!cancelled && data) {
29243
- setSummary({
29244
- enabled: Boolean(data.enabled),
29245
- channels: data.channels ?? []
29246
- });
29247
- }
29248
- }).catch(() => void 0);
29249
- return () => {
29250
- cancelled = true;
29251
- };
29252
- }, [
29253
- eventId
29254
- ]);
29255
- if (!summary?.enabled) {
29256
- return /* @__PURE__ */ React.createElement("p", {
29257
- className: "text-sm text-gray-500"
29258
- }, "Order notifications: disabled");
29259
- }
29260
- const ch = summary.channels.length ? summary.channels.join(", ") : "none";
29261
- return /* @__PURE__ */ React.createElement("p", {
29262
- className: "text-sm text-gray-700 dark:text-gray-300"
29263
- }, "Order notifications: ", /* @__PURE__ */ React.createElement("span", {
29264
- className: "font-medium text-green-700 dark:text-green-400"
29265
- }, "enabled"), " (", ch, ")");
29266
- }
29267
- var panelCls, subPanelCls, labelCls5, hintCls;
29268
- var init_EventNotificationSettings = __esm({
29269
- "src/admin/components/EventNotificationSettings.tsx"() {
29270
- "use client";
29271
- init_button();
29272
- init_input();
29273
- init_label();
29274
- init_textarea();
29275
- panelCls = "rounded-lg border border-gray-200 bg-white p-4 sm:p-5 dark:border-gray-600 dark:bg-gray-900/30";
29276
- subPanelCls = "rounded-md border border-gray-100 bg-gray-50/80 p-4 space-y-4 dark:border-gray-700 dark:bg-gray-800/40";
29277
- labelCls5 = "block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1.5";
29278
- hintCls = "text-xs text-gray-500 dark:text-gray-400 leading-relaxed";
29279
- __name(VariableChip, "VariableChip");
29280
- __name(ChannelToggle, "ChannelToggle");
29281
- __name(EventNotificationSettings, "EventNotificationSettings");
29282
- __name(EventNotificationSummary, "EventNotificationSummary");
29283
- }
29284
- });
29285
29505
 
29286
29506
  // src/lib/social-media-links.ts
29287
29507
  function isValidHttpUrl(value) {
@@ -29382,7 +29602,7 @@ function SocialMediaLinksForm({ fields, values, onChange }) {
29382
29602
  return /* @__PURE__ */ React.createElement("div", {
29383
29603
  key: field.key
29384
29604
  }, /* @__PURE__ */ React.createElement("label", {
29385
- className: labelCls6
29605
+ className: labelCls5
29386
29606
  }, field.label), /* @__PURE__ */ React.createElement("div", {
29387
29607
  className: "relative"
29388
29608
  }, Icon2 ? /* @__PURE__ */ React.createElement(Icon2, {
@@ -29503,52 +29723,14 @@ function SupportedCurrenciesPicker({ currencies, defaultCurrency, supported, onD
29503
29723
  className: "mt-1 text-xs text-gray-500"
29504
29724
  }, "Default currency is always included.")));
29505
29725
  }
29506
- function MultiCurrencyPriceFields({ defaultCurrency, currencies, defaultPrice, additionalPrices, onDefaultPriceChange, onAdditionalPriceChange, labelCls: labelClassName = "block text-xs font-medium text-gray-600 mb-1", inputCls: inputClassName = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm" }) {
29507
- const base = defaultCurrency.trim().toUpperCase() || "INR";
29508
- const others = currencies.filter((c) => c.code.toUpperCase() !== base);
29509
- return /* @__PURE__ */ React.createElement("div", {
29510
- className: "space-y-4"
29511
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
29512
- className: labelClassName
29513
- }, base, " price ", /* @__PURE__ */ React.createElement("span", {
29514
- className: "text-red-600"
29515
- }, "*")), /* @__PURE__ */ React.createElement("input", {
29516
- type: "number",
29517
- min: 0,
29518
- step: "any",
29519
- value: defaultPrice,
29520
- onChange: /* @__PURE__ */ __name((e) => onDefaultPriceChange(e.target.value), "onChange"),
29521
- className: inputClassName,
29522
- required: true
29523
- })), others.length > 0 ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
29524
- className: `${labelClassName} mb-2`
29525
- }, "Additional currencies (optional)"), /* @__PURE__ */ React.createElement("div", {
29526
- className: "grid gap-3 sm:grid-cols-2"
29527
- }, others.map((c) => {
29528
- const code = c.code.toUpperCase();
29529
- return /* @__PURE__ */ React.createElement("div", {
29530
- key: code
29531
- }, /* @__PURE__ */ React.createElement("label", {
29532
- className: labelClassName
29533
- }, code), /* @__PURE__ */ React.createElement("input", {
29534
- type: "number",
29535
- min: 0,
29536
- step: "any",
29537
- value: additionalPrices[code] ?? "",
29538
- onChange: /* @__PURE__ */ __name((e) => onAdditionalPriceChange(code, e.target.value), "onChange"),
29539
- className: inputClassName,
29540
- placeholder: "Optional"
29541
- }));
29542
- }))) : null);
29543
- }
29544
- var inputCls5, labelCls6, ICONS;
29726
+ var inputCls5, labelCls5, ICONS;
29545
29727
  var init_EventManagementFields = __esm({
29546
29728
  "src/components/Admin/EventManagementFields.tsx"() {
29547
29729
  "use client";
29548
29730
  init_social_brand_icons();
29549
29731
  init_social_media_links();
29550
29732
  inputCls5 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm pl-9";
29551
- labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
29733
+ labelCls5 = "block text-xs font-medium text-gray-600 mb-1";
29552
29734
  ICONS = {
29553
29735
  facebook: FacebookBrandIcon,
29554
29736
  instagram: InstagramBrandIcon,
@@ -29562,7 +29744,6 @@ var init_EventManagementFields = __esm({
29562
29744
  __name(SocialMediaLinksDisplay, "SocialMediaLinksDisplay");
29563
29745
  __name(TimezoneSelect, "TimezoneSelect");
29564
29746
  __name(SupportedCurrenciesPicker, "SupportedCurrenciesPicker");
29565
- __name(MultiCurrencyPriceFields, "MultiCurrencyPriceFields");
29566
29747
  }
29567
29748
  });
29568
29749
 
@@ -29714,28 +29895,11 @@ function intersectSupportedCurrencies(supported, defaultCurrency, options) {
29714
29895
  ])
29715
29896
  ];
29716
29897
  }
29717
- function currencyOptionsIncluding(options, codes) {
29718
- const map = new Map(options.map((o) => [
29719
- o.code.toUpperCase(),
29720
- o
29721
- ]));
29722
- for (const code of codes) {
29723
- const normalized = code.trim().toUpperCase();
29724
- if (!normalized || map.has(normalized)) continue;
29725
- map.set(normalized, {
29726
- code: normalized
29727
- });
29728
- }
29729
- return [
29730
- ...map.values()
29731
- ].sort((a, b) => a.code.localeCompare(b.code));
29732
- }
29733
29898
  var init_currency_options = __esm({
29734
29899
  "src/lib/currency-options.ts"() {
29735
29900
  __name(parseCurrencyApiRows, "parseCurrencyApiRows");
29736
29901
  __name(fetchActiveCurrencyOptions, "fetchActiveCurrencyOptions");
29737
29902
  __name(intersectSupportedCurrencies, "intersectSupportedCurrencies");
29738
- __name(currencyOptionsIncluding, "currencyOptionsIncluding");
29739
29903
  }
29740
29904
  });
29741
29905
 
@@ -29924,7 +30088,7 @@ __export(EventEditPage_exports, {
29924
30088
  });
29925
30089
  function RequiredLabel({ children }) {
29926
30090
  return /* @__PURE__ */ React.createElement("label", {
29927
- className: labelCls7
30091
+ className: labelCls6
29928
30092
  }, children, " ", /* @__PURE__ */ React.createElement("span", {
29929
30093
  className: "text-red-600"
29930
30094
  }, "*"));
@@ -30369,21 +30533,21 @@ function EventEditPage({ eventId }) {
30369
30533
  }, /* @__PURE__ */ React.createElement("div", {
30370
30534
  className: "sm:col-span-2"
30371
30535
  }, /* @__PURE__ */ React.createElement("label", {
30372
- className: labelCls7
30536
+ className: labelCls6
30373
30537
  }, "Name"), /* @__PURE__ */ React.createElement("input", {
30374
30538
  type: "text",
30375
30539
  value: name,
30376
30540
  onChange: /* @__PURE__ */ __name((e) => setName(e.target.value), "onChange"),
30377
30541
  className: inputCls6
30378
30542
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30379
- className: labelCls7
30543
+ className: labelCls6
30380
30544
  }, "Slug"), /* @__PURE__ */ React.createElement("input", {
30381
30545
  type: "text",
30382
30546
  value: slug,
30383
30547
  onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
30384
30548
  className: inputCls6
30385
30549
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30386
- className: labelCls7
30550
+ className: labelCls6
30387
30551
  }, "Sort order"), /* @__PURE__ */ React.createElement("input", {
30388
30552
  type: "number",
30389
30553
  value: sortOrder,
@@ -30392,7 +30556,7 @@ function EventEditPage({ eventId }) {
30392
30556
  })), /* @__PURE__ */ React.createElement("div", {
30393
30557
  className: "sm:col-span-2"
30394
30558
  }, /* @__PURE__ */ React.createElement("label", {
30395
- className: labelCls7
30559
+ className: labelCls6
30396
30560
  }, "Description"), /* @__PURE__ */ React.createElement("div", {
30397
30561
  className: "rounded-md border border-gray-300 bg-white overflow-hidden"
30398
30562
  }, /* @__PURE__ */ React.createElement(JoditRichText, {
@@ -30403,7 +30567,7 @@ function EventEditPage({ eventId }) {
30403
30567
  }))), /* @__PURE__ */ React.createElement("div", {
30404
30568
  className: "sm:col-span-2"
30405
30569
  }, /* @__PURE__ */ React.createElement("label", {
30406
- className: labelCls7
30570
+ className: labelCls6
30407
30571
  }, "Entity types"), /* @__PURE__ */ React.createElement("div", {
30408
30572
  className: "flex flex-wrap gap-2"
30409
30573
  }, ENTITY_TYPE_OPTIONS.map((type) => /* @__PURE__ */ React.createElement("label", {
@@ -30419,7 +30583,7 @@ function EventEditPage({ eventId }) {
30419
30583
  }, type)))), /* @__PURE__ */ React.createElement("div", {
30420
30584
  className: "mt-3 space-y-2"
30421
30585
  }, /* @__PURE__ */ React.createElement("label", {
30422
- className: labelCls7
30586
+ className: labelCls6
30423
30587
  }, "Custom entity type"), /* @__PURE__ */ React.createElement("div", {
30424
30588
  className: "flex flex-wrap gap-2"
30425
30589
  }, /* @__PURE__ */ React.createElement("input", {
@@ -30459,7 +30623,7 @@ function EventEditPage({ eventId }) {
30459
30623
  onChange: setBannerImageUrl,
30460
30624
  previewVariant: "banner",
30461
30625
  inputClassName: inputCls6,
30462
- labelClassName: labelCls7
30626
+ labelClassName: labelCls6
30463
30627
  })), /* @__PURE__ */ React.createElement("div", {
30464
30628
  className: "sm:col-span-2"
30465
30629
  }, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
@@ -30468,9 +30632,9 @@ function EventEditPage({ eventId }) {
30468
30632
  onChange: setLogoUrl,
30469
30633
  previewVariant: "logo",
30470
30634
  inputClassName: inputCls6,
30471
- labelClassName: labelCls7
30635
+ labelClassName: labelCls6
30472
30636
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30473
- className: labelCls7
30637
+ className: labelCls6
30474
30638
  }, "Pricing type"), /* @__PURE__ */ React.createElement("select", {
30475
30639
  value: pricingType,
30476
30640
  onChange: /* @__PURE__ */ __name((e) => setPricingType(e.target.value), "onChange"),
@@ -30482,7 +30646,7 @@ function EventEditPage({ eventId }) {
30482
30646
  }, "Free"), /* @__PURE__ */ React.createElement("option", {
30483
30647
  value: "paid"
30484
30648
  }, "Paid"))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30485
- className: labelCls7
30649
+ className: labelCls6
30486
30650
  }, "Mode"), /* @__PURE__ */ React.createElement("select", {
30487
30651
  value: entityMode,
30488
30652
  onChange: /* @__PURE__ */ __name((e) => setEntityMode(e.target.value), "onChange"),
@@ -30502,7 +30666,7 @@ function EventEditPage({ eventId }) {
30502
30666
  }, /* @__PURE__ */ React.createElement("div", {
30503
30667
  className: "sm:col-span-2"
30504
30668
  }, /* @__PURE__ */ React.createElement("label", {
30505
- className: labelCls7
30669
+ className: labelCls6
30506
30670
  }, "Venue"), /* @__PURE__ */ React.createElement("input", {
30507
30671
  type: "text",
30508
30672
  value: venue,
@@ -30511,7 +30675,7 @@ function EventEditPage({ eventId }) {
30511
30675
  })), /* @__PURE__ */ React.createElement("div", {
30512
30676
  className: "sm:col-span-2"
30513
30677
  }, /* @__PURE__ */ React.createElement("label", {
30514
- className: labelCls7
30678
+ className: labelCls6
30515
30679
  }, "Additional venue details"), /* @__PURE__ */ React.createElement("textarea", {
30516
30680
  value: additionalVenueDetails,
30517
30681
  onChange: /* @__PURE__ */ __name((e) => setAdditionalVenueDetails(e.target.value.slice(0, ADDITIONAL_VENUE_MAX_CHARS)), "onChange"),
@@ -30522,14 +30686,14 @@ function EventEditPage({ eventId }) {
30522
30686
  }), /* @__PURE__ */ React.createElement("p", {
30523
30687
  className: "mt-1 text-xs text-gray-500 text-right"
30524
30688
  }, additionalVenueDetails.length, " / ", ADDITIONAL_VENUE_MAX_CHARS, " characters")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30525
- className: labelCls7
30689
+ className: labelCls6
30526
30690
  }, "City"), /* @__PURE__ */ React.createElement("input", {
30527
30691
  type: "text",
30528
30692
  value: city,
30529
30693
  onChange: /* @__PURE__ */ __name((e) => setCity(e.target.value), "onChange"),
30530
30694
  className: inputCls6
30531
30695
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30532
- className: labelCls7
30696
+ className: labelCls6
30533
30697
  }, "Country"), /* @__PURE__ */ React.createElement("input", {
30534
30698
  type: "text",
30535
30699
  value: country,
@@ -30560,14 +30724,14 @@ function EventEditPage({ eventId }) {
30560
30724
  className: inputCls6,
30561
30725
  required: true
30562
30726
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30563
- className: labelCls7
30727
+ className: labelCls6
30564
30728
  }, "Registration opens"), /* @__PURE__ */ React.createElement("input", {
30565
30729
  type: "datetime-local",
30566
30730
  value: registrationOpensAt,
30567
30731
  onChange: /* @__PURE__ */ __name((e) => setRegistrationOpensAt(e.target.value), "onChange"),
30568
30732
  className: inputCls6
30569
30733
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30570
- className: labelCls7
30734
+ className: labelCls6
30571
30735
  }, "Registration closes"), /* @__PURE__ */ React.createElement("input", {
30572
30736
  type: "datetime-local",
30573
30737
  value: registrationClosesAt,
@@ -30588,20 +30752,20 @@ function EventEditPage({ eventId }) {
30588
30752
  onDefaultChange: setDefaultCurrency,
30589
30753
  onSupportedChange: setSupportedCurrencies,
30590
30754
  inputCls: inputCls6,
30591
- labelCls: labelCls7
30755
+ labelCls: labelCls6
30592
30756
  }) : /* @__PURE__ */ React.createElement("p", {
30593
30757
  className: "text-sm text-gray-500"
30594
30758
  }, "No active currencies configured. Add currencies in Store settings first."), /* @__PURE__ */ React.createElement("div", {
30595
30759
  className: "grid gap-3 sm:grid-cols-2"
30596
30760
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30597
- className: labelCls7
30761
+ className: labelCls6
30598
30762
  }, "Official website URL"), /* @__PURE__ */ React.createElement("input", {
30599
30763
  type: "url",
30600
30764
  value: officialWebsiteUrl,
30601
30765
  onChange: /* @__PURE__ */ __name((e) => setOfficialWebsiteUrl(e.target.value), "onChange"),
30602
30766
  className: inputCls6
30603
30767
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30604
- className: labelCls7
30768
+ className: labelCls6
30605
30769
  }, "Support contact"), /* @__PURE__ */ React.createElement("input", {
30606
30770
  type: "text",
30607
30771
  value: supportContact,
@@ -30610,7 +30774,7 @@ function EventEditPage({ eventId }) {
30610
30774
  })), /* @__PURE__ */ React.createElement("div", {
30611
30775
  className: "sm:col-span-2"
30612
30776
  }, /* @__PURE__ */ React.createElement("label", {
30613
- className: labelCls7
30777
+ className: labelCls6
30614
30778
  }, "Contact form"), /* @__PURE__ */ React.createElement("select", {
30615
30779
  value: contactFormId ?? "",
30616
30780
  onChange: /* @__PURE__ */ __name((e) => setContactFormId(e.target.value ? Number(e.target.value) : null), "onChange"),
@@ -30625,7 +30789,7 @@ function EventEditPage({ eventId }) {
30625
30789
  }, "Attendee registration form used during checkout for this event.")), /* @__PURE__ */ React.createElement("div", {
30626
30790
  className: "sm:col-span-2 grid gap-4 sm:grid-cols-2 sm:items-end"
30627
30791
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30628
- className: labelCls7
30792
+ className: labelCls6
30629
30793
  }, "Max group purchase quantity"), /* @__PURE__ */ React.createElement("input", {
30630
30794
  type: "number",
30631
30795
  value: maxGroupPurchaseQuantity,
@@ -30661,13 +30825,7 @@ function EventEditPage({ eventId }) {
30661
30825
  ...prev,
30662
30826
  [key]: value
30663
30827
  })), "onChange")
30664
- })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
30665
- className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3"
30666
- }, "Order notifications"), eventRecordId ? /* @__PURE__ */ React.createElement(EventNotificationSettings, {
30667
- eventId: eventRecordId
30668
- }) : /* @__PURE__ */ React.createElement("p", {
30669
- className: "text-sm text-gray-500"
30670
- }, "Save the event first to configure order notification channels and templates."))))
30828
+ }))))
30671
30829
  }), showEventProducts ? /* @__PURE__ */ React.createElement("div", {
30672
30830
  className: "border-t border-gray-200 px-4 py-4 sm:px-6"
30673
30831
  }, /* @__PURE__ */ React.createElement(EventProductsSection, {
@@ -30675,7 +30833,7 @@ function EventEditPage({ eventId }) {
30675
30833
  returnUrl: eventEditUrl
30676
30834
  })) : null);
30677
30835
  }
30678
- var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls5, labelCls7, inputCls6, ENTITY_TYPE_OPTIONS;
30836
+ var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls5, labelCls6, inputCls6, ENTITY_TYPE_OPTIONS;
30679
30837
  var init_EventEditPage = __esm({
30680
30838
  "src/admin/pages/EventEditPage.tsx"() {
30681
30839
  "use client";
@@ -30685,7 +30843,6 @@ var init_EventEditPage = __esm({
30685
30843
  init_ImageOrUrlField();
30686
30844
  init_JoditRichText();
30687
30845
  init_EventProductsSection();
30688
- init_EventNotificationSettings();
30689
30846
  init_EventManagementFields();
30690
30847
  init_event_named_lists();
30691
30848
  init_social_media_links();
@@ -30698,7 +30855,7 @@ var init_EventEditPage = __esm({
30698
30855
  EVENT_SOCIAL_KEYS = EVENT_SOCIAL_FIELDS.map((f) => f.key);
30699
30856
  isCreate4 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
30700
30857
  sectionCls5 = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50";
30701
- labelCls7 = "block text-xs font-medium text-gray-600 mb-1";
30858
+ labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
30702
30859
  inputCls6 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
30703
30860
  __name(RequiredLabel, "RequiredLabel");
30704
30861
  ENTITY_TYPE_OPTIONS = [
@@ -30722,25 +30879,14 @@ function formatDateTimeLocal(value) {
30722
30879
  if (isNaN(date.getTime())) return "";
30723
30880
  return date.toISOString().slice(0, 16);
30724
30881
  }
30725
- async function fetchEventPricing(eventId) {
30882
+ async function fetchEventDefaultCurrency(eventId) {
30726
30883
  try {
30727
30884
  const res = await fetch(`/api/events/${eventId}`);
30728
- if (!res.ok) return DEFAULT_PRICING;
30885
+ if (!res.ok) return "INR";
30729
30886
  const data = await res.json();
30730
- const defaultCurrency = String(data.defaultCurrency ?? "INR").trim().toUpperCase() || "INR";
30731
- const supported = Array.isArray(data.supportedCurrencies) ? data.supportedCurrencies.map((c) => String(c).trim().toUpperCase()).filter((c) => Boolean(c)) : [
30732
- defaultCurrency
30733
- ];
30734
- const set = new Set(supported);
30735
- set.add(defaultCurrency);
30736
- return {
30737
- defaultCurrency,
30738
- supportedCurrencies: [
30739
- ...set
30740
- ]
30741
- };
30887
+ return String(data.defaultCurrency ?? "INR").trim().toUpperCase() || "INR";
30742
30888
  } catch {
30743
- return DEFAULT_PRICING;
30889
+ return "INR";
30744
30890
  }
30745
30891
  }
30746
30892
  async function validateComboProductInventory(productIds) {
@@ -30782,10 +30928,8 @@ function ComboEditPage({ comboId }) {
30782
30928
  const [name, setName] = React26.useState("");
30783
30929
  const [desc, setDesc] = React26.useState("");
30784
30930
  const [eventId, setEventId] = React26.useState("");
30785
- const [defaultPriceStr, setDefaultPriceStr] = React26.useState("");
30786
- const [additionalPrices, setAdditionalPrices] = React26.useState({});
30787
- const [pricingConfig, setPricingConfig] = React26.useState(DEFAULT_PRICING);
30788
- const [currencySchemaOptions, setCurrencySchemaOptions] = React26.useState([]);
30931
+ const [priceStr, setPriceStr] = React26.useState("");
30932
+ const [defaultCurrency, setDefaultCurrency] = React26.useState("INR");
30789
30933
  const [minSelectableItems, setMinSelectableItems] = React26.useState(1);
30790
30934
  const [maxSelectableItems, setMaxSelectableItems] = React26.useState(1);
30791
30935
  const [status, setStatus] = React26.useState("active");
@@ -30795,23 +30939,14 @@ function ComboEditPage({ comboId }) {
30795
30939
  const [productOptions, setProductOptions] = React26.useState([]);
30796
30940
  const [fixedItems, setFixedItems] = React26.useState([]);
30797
30941
  const [addonItems, setAddonItems] = React26.useState([]);
30798
- React26.useEffect(() => {
30799
- let cancelled = false;
30800
- fetchActiveCurrencyOptions().then(({ options }) => {
30801
- if (!cancelled && options.length) setCurrencySchemaOptions(options);
30802
- });
30803
- return () => {
30804
- cancelled = true;
30805
- };
30806
- }, []);
30807
30942
  React26.useEffect(() => {
30808
30943
  if (!eventId) {
30809
- setPricingConfig(DEFAULT_PRICING);
30944
+ setDefaultCurrency("INR");
30810
30945
  return;
30811
30946
  }
30812
30947
  let cancelled = false;
30813
- fetchEventPricing(eventId).then((config) => {
30814
- if (!cancelled) setPricingConfig(config);
30948
+ fetchEventDefaultCurrency(eventId).then((code) => {
30949
+ if (!cancelled) setDefaultCurrency(code);
30815
30950
  });
30816
30951
  return () => {
30817
30952
  cancelled = true;
@@ -30819,10 +30954,6 @@ function ComboEditPage({ comboId }) {
30819
30954
  }, [
30820
30955
  eventId
30821
30956
  ]);
30822
- const pricingCurrencyOptions = currencyOptionsIncluding(currencySchemaOptions, [
30823
- pricingConfig.defaultCurrency,
30824
- ...pricingConfig.supportedCurrencies
30825
- ]).filter((c) => pricingConfig.supportedCurrencies.map((x) => x.toUpperCase()).includes(c.code.toUpperCase()));
30826
30957
  React26.useEffect(() => {
30827
30958
  let cancelled = false;
30828
30959
  (async () => {
@@ -30911,11 +31042,11 @@ function ComboEditPage({ comboId }) {
30911
31042
  setName(data.name ?? "");
30912
31043
  setDesc(data.desc ?? "");
30913
31044
  setEventId(data.eventId != null ? String(data.eventId) : "");
30914
- const eventPricing = data.eventId != null ? await fetchEventPricing(String(data.eventId)) : DEFAULT_PRICING;
30915
- if (!cancelled) setPricingConfig(eventPricing);
30916
- const { defaultPrice, additional } = currencyPricesToForm(eventPricing.defaultCurrency, data.price != null ? Number(data.price) : null, data.currencyPrices);
30917
- setDefaultPriceStr(defaultPrice);
30918
- setAdditionalPrices(additional);
31045
+ if (data.eventId != null) {
31046
+ const currency = await fetchEventDefaultCurrency(String(data.eventId));
31047
+ if (!cancelled) setDefaultCurrency(currency);
31048
+ }
31049
+ setPriceStr(data.price != null && Number.isFinite(Number(data.price)) ? String(data.price) : "");
30919
31050
  setMinSelectableItems(Number(data.minSelectableItems) || 1);
30920
31051
  setMaxSelectableItems(Number(data.maxSelectableItems) || 1);
30921
31052
  setStatus(data.status ?? "active");
@@ -30966,10 +31097,6 @@ function ComboEditPage({ comboId }) {
30966
31097
  create,
30967
31098
  duplicateSourceId
30968
31099
  ]);
30969
- /* @__PURE__ */ new Set([
30970
- ...fixedItems.map((i) => i.productId),
30971
- ...addonItems.map((i) => i.productId)
30972
- ]);
30973
31100
  const availableForFixed = productOptions.filter((p) => !addonItems.some((i) => i.productId === p.value));
30974
31101
  const availableForAddon = productOptions.filter((p) => !fixedItems.some((i) => i.productId === p.value));
30975
31102
  const addFixed = /* @__PURE__ */ __name((val) => {
@@ -31010,16 +31137,16 @@ function ComboEditPage({ comboId }) {
31010
31137
  ]);
31011
31138
  return;
31012
31139
  }
31013
- if (!defaultPriceStr.trim()) {
31140
+ if (!priceStr.trim()) {
31014
31141
  setErrors([
31015
- `${pricingConfig.defaultCurrency} price is required`
31142
+ `Price (${defaultCurrency}) is required`
31016
31143
  ]);
31017
31144
  return;
31018
31145
  }
31019
- const pricingPayload = formToCurrencyPricesPayload(pricingConfig.defaultCurrency, defaultPriceStr, additionalPrices);
31020
- if (!pricingPayload) {
31146
+ const price = Number(priceStr);
31147
+ if (!Number.isFinite(price) || price < 0) {
31021
31148
  setErrors([
31022
- `${pricingConfig.defaultCurrency} price must be a valid number`
31149
+ `Price (${defaultCurrency}) must be a valid non-negative number`
31023
31150
  ]);
31024
31151
  return;
31025
31152
  }
@@ -31067,8 +31194,8 @@ function ComboEditPage({ comboId }) {
31067
31194
  name: trimmedName,
31068
31195
  desc: desc || null,
31069
31196
  eventId: Number(trimmedEventId),
31070
- price: pricingPayload.price,
31071
- currencyPrices: pricingPayload.currencyPrices,
31197
+ price,
31198
+ currencyPrices: null,
31072
31199
  minSelectableItems,
31073
31200
  maxSelectableItems,
31074
31201
  status,
@@ -31235,21 +31362,19 @@ function ComboEditPage({ comboId }) {
31235
31362
  className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
31236
31363
  }, "Pricing & add-on selection"), /* @__PURE__ */ React.createElement("div", {
31237
31364
  className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4"
31238
- }, eventId ? /* @__PURE__ */ React.createElement(MultiCurrencyPriceFields, {
31239
- defaultCurrency: pricingConfig.defaultCurrency,
31240
- currencies: pricingCurrencyOptions,
31241
- defaultPrice: defaultPriceStr,
31242
- additionalPrices,
31243
- onDefaultPriceChange: setDefaultPriceStr,
31244
- onAdditionalPriceChange: /* @__PURE__ */ __name((code, value) => setAdditionalPrices((prev) => ({
31245
- ...prev,
31246
- [code]: value
31247
- })), "onAdditionalPriceChange"),
31248
- labelCls: "block text-xs font-medium text-gray-600 mb-1",
31249
- inputCls: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
31250
- }) : /* @__PURE__ */ React.createElement("p", {
31251
- className: "text-sm text-gray-500"
31252
- }, "Select an event to configure combo pricing currencies."), /* @__PURE__ */ React.createElement("div", {
31365
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
31366
+ className: "block text-xs font-medium text-gray-600 mb-1"
31367
+ }, "Price (", defaultCurrency, ") *"), /* @__PURE__ */ React.createElement("input", {
31368
+ type: "number",
31369
+ min: 0,
31370
+ step: "0.01",
31371
+ value: priceStr,
31372
+ onChange: /* @__PURE__ */ __name((e) => setPriceStr(e.target.value), "onChange"),
31373
+ disabled: !eventId,
31374
+ className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm disabled:bg-gray-100"
31375
+ }), /* @__PURE__ */ React.createElement("p", {
31376
+ className: "text-xs text-gray-400 mt-1"
31377
+ }, eventId ? "Other currencies use the event\u2019s supported currencies and exchange rates." : "Select an event to set the combo price.")), /* @__PURE__ */ React.createElement("div", {
31253
31378
  className: "grid grid-cols-2 gap-4"
31254
31379
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
31255
31380
  className: "block text-xs font-medium text-gray-600 mb-1"
@@ -31307,26 +31432,17 @@ function ComboEditPage({ comboId }) {
31307
31432
  sidebar: /* @__PURE__ */ React.createElement(React.Fragment, null)
31308
31433
  }));
31309
31434
  }
31310
- var isCreate5, DEFAULT_PRICING;
31435
+ var isCreate5;
31311
31436
  var init_ComboEditPage = __esm({
31312
31437
  "src/admin/pages/ComboEditPage.tsx"() {
31313
31438
  "use client";
31314
31439
  init_admin_list_return_url();
31315
31440
  init_DetailPageLayout();
31316
31441
  init_DetailPageHeader();
31317
- init_EventManagementFields();
31318
- init_currency_options();
31319
- init_currency_prices();
31320
31442
  init_inventory_validation();
31321
31443
  isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
31322
31444
  __name(formatDateTimeLocal, "formatDateTimeLocal");
31323
- DEFAULT_PRICING = {
31324
- defaultCurrency: "INR",
31325
- supportedCurrencies: [
31326
- "INR"
31327
- ]
31328
- };
31329
- __name(fetchEventPricing, "fetchEventPricing");
31445
+ __name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
31330
31446
  __name(validateComboProductInventory, "validateComboProductInventory");
31331
31447
  __name(ComboEditPage, "ComboEditPage");
31332
31448
  }
@@ -32093,35 +32209,48 @@ var VendorCategoryWorkspacePage_exports = {};
32093
32209
  __export(VendorCategoryWorkspacePage_exports, {
32094
32210
  default: () => VendorCategoryWorkspacePage
32095
32211
  });
32096
- function buildAdminProductColumns(base) {
32212
+ function buildAdminProductColumns(base, multiVendorEnabled, eventsEnabled) {
32213
+ const extraColumns = [
32214
+ ...multiVendorEnabled ? [
32215
+ VENDOR_EXTRA_COLUMN
32216
+ ] : [],
32217
+ ...eventsEnabled ? [
32218
+ EVENT_EXTRA_COLUMN
32219
+ ] : []
32220
+ ];
32097
32221
  const cols = base.filter((c) => c.field && !CATEGORY_PRODUCT_HIDDEN_FIELDS.has(c.field));
32098
32222
  const nameIdx = cols.findIndex((c) => c.field === "name");
32099
32223
  if (nameIdx < 0) return [
32100
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32224
+ ...extraColumns,
32101
32225
  ...cols
32102
32226
  ];
32103
32227
  return [
32104
32228
  ...cols.slice(0, nameIdx + 1),
32105
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32229
+ ...extraColumns,
32106
32230
  ...cols.slice(nameIdx + 1)
32107
32231
  ];
32108
32232
  }
32109
- function buildAdminAllProductColumns(base) {
32233
+ function buildAllProductColumns(base, multiVendorEnabled, eventsEnabled) {
32234
+ const extraColumns = [
32235
+ ...multiVendorEnabled ? [
32236
+ VENDOR_EXTRA_COLUMN
32237
+ ] : [],
32238
+ ...eventsEnabled ? [
32239
+ EVENT_EXTRA_COLUMN
32240
+ ] : []
32241
+ ];
32110
32242
  const cols = base.filter((c) => Boolean(c.field));
32111
32243
  const nameIdx = cols.findIndex((c) => c.field === "name");
32112
32244
  if (nameIdx < 0) return [
32113
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32245
+ ...extraColumns,
32114
32246
  ...cols
32115
32247
  ];
32116
32248
  return [
32117
32249
  ...cols.slice(0, nameIdx + 1),
32118
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32250
+ ...extraColumns,
32119
32251
  ...cols.slice(nameIdx + 1)
32120
32252
  ];
32121
32253
  }
32122
- function buildVendorProductColumns(base) {
32123
- return base.filter((c) => c.field !== "categoryId" && c.field !== "vendorId");
32124
- }
32125
32254
  function withCollectionRelationApi(columns, categoryId, vendorPortal) {
32126
32255
  const relationApi = collectionsRelationApi({
32127
32256
  vendorPortal,
@@ -32133,47 +32262,34 @@ function withCollectionRelationApi(columns, categoryId, vendorPortal) {
32133
32262
  } : col);
32134
32263
  }
32135
32264
  function VendorCategoryWorkspacePage() {
32136
- const router = navigation.useRouter();
32137
32265
  const searchParams = navigation.useSearchParams();
32138
32266
  const { data: session } = react.useSession();
32139
32267
  const vendorPortal = isVendorPortalUser(session?.user);
32268
+ const { multiVendorEnabled, eventsEnabled } = React26.useContext(exports.AdminConfigContext);
32140
32269
  const { categories, loading, error } = useCatalogCategories();
32141
32270
  const categoryIdParam = searchParams.get("categoryId")?.trim() ?? "";
32142
32271
  const activeCategoryId = React26.useMemo(() => {
32143
32272
  if (categoryIdParam && categories.some((c) => String(c.id) === categoryIdParam)) {
32144
32273
  return categoryIdParam;
32145
32274
  }
32146
- if (vendorPortal) {
32147
- const first = categories[0];
32148
- return first ? String(first.id) : "";
32149
- }
32150
32275
  return "";
32151
32276
  }, [
32152
32277
  categoryIdParam,
32153
- categories,
32154
- vendorPortal
32155
- ]);
32156
- React26.useEffect(() => {
32157
- if (!vendorPortal) return;
32158
- if (!activeCategoryId || activeCategoryId === categoryIdParam) return;
32159
- router.replace(vendorCategoryWorkspaceUrl(activeCategoryId));
32160
- }, [
32161
- activeCategoryId,
32162
- categoryIdParam,
32163
- router,
32164
- vendorPortal
32278
+ categories
32165
32279
  ]);
32166
32280
  const activeCategory = categories.find((c) => String(c.id) === activeCategoryId);
32167
- const showAllProducts = !vendorPortal && !activeCategoryId;
32168
- const workspaceFrom = activeCategoryId ? vendorCategoryWorkspaceUrl(activeCategoryId) : "/admin/products";
32281
+ const showAllProducts = !activeCategoryId;
32282
+ const workspaceFrom = activeCategoryId ? `/admin/products?categoryId=${activeCategoryId}` : "/admin/products";
32169
32283
  const itemLabel = activeCategory ? categorySingularName(activeCategory.name) : "Product";
32170
32284
  const productColumns2 = React26.useMemo(() => {
32171
- const base = vendorPortal ? buildVendorProductColumns(exports.STORE_CRUD_CONFIGS.products.columns) : showAllProducts ? buildAdminAllProductColumns(exports.STORE_CRUD_CONFIGS.products.columns) : buildAdminProductColumns(exports.STORE_CRUD_CONFIGS.products.columns);
32285
+ const base = showAllProducts ? buildAllProductColumns(exports.STORE_CRUD_CONFIGS.products.columns, multiVendorEnabled !== false, eventsEnabled !== false) : buildAdminProductColumns(exports.STORE_CRUD_CONFIGS.products.columns, multiVendorEnabled !== false, eventsEnabled !== false);
32172
32286
  return withCollectionRelationApi(base, activeCategoryId, vendorPortal);
32173
32287
  }, [
32174
32288
  vendorPortal,
32175
32289
  activeCategoryId,
32176
- showAllProducts
32290
+ showAllProducts,
32291
+ multiVendorEnabled,
32292
+ eventsEnabled
32177
32293
  ]);
32178
32294
  const productFilterColumns2 = React26.useMemo(() => productColumns2, [
32179
32295
  productColumns2
@@ -32190,20 +32306,8 @@ function VendorCategoryWorkspacePage() {
32190
32306
  className: "text-red-600 text-sm"
32191
32307
  }, error));
32192
32308
  }
32193
- if (categories.length === 0) {
32194
- return /* @__PURE__ */ React26__namespace.default.createElement("div", {
32195
- className: "rounded-lg bg-white p-6 shadow-md"
32196
- }, /* @__PURE__ */ React26__namespace.default.createElement("h1", {
32197
- className: "text-lg font-semibold text-gray-900"
32198
- }, "Store"), /* @__PURE__ */ React26__namespace.default.createElement("p", {
32199
- className: "mt-2 text-sm text-gray-600"
32200
- }, "No catalog categories are available yet. Ask your platform administrator to add store categories."));
32201
- }
32202
- if (!showAllProducts && (!activeCategoryId || !activeCategory)) {
32203
- return null;
32204
- }
32205
- const listTitle = showAllProducts ? "Products" : activeCategory.name;
32206
- const listKey = showAllProducts ? "products-all-admin" : `products-${activeCategoryId}-${vendorPortal ? "vendor" : "admin"}`;
32309
+ const listTitle = showAllProducts ? "Products" : activeCategory?.name ?? "Products";
32310
+ const listKey = showAllProducts ? "products-all" : `products-${activeCategoryId}`;
32207
32311
  return /* @__PURE__ */ React26__namespace.default.createElement("div", {
32208
32312
  className: "rounded-lg bg-white shadow-md min-h-[420px]"
32209
32313
  }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
@@ -32227,12 +32331,10 @@ function VendorCategoryWorkspacePage() {
32227
32331
  ...activeCategoryId ? {
32228
32332
  categoryId: activeCategoryId
32229
32333
  } : {},
32230
- ...!vendorPortal ? {
32231
- includeEventNames: "1"
32232
- } : {}
32334
+ includeEventNames: "1"
32233
32335
  },
32234
32336
  emptyState: {
32235
- title: showAllProducts ? "No products found" : `No ${activeCategory.name.toLowerCase()} found`,
32337
+ title: showAllProducts ? "No products found" : `No ${(activeCategory?.name ?? "product").toLowerCase()} found`,
32236
32338
  description: showAllProducts ? "Add a product to get started." : `Add a ${itemLabel.toLowerCase()} and select a collection for it.`,
32237
32339
  action: /* @__PURE__ */ React26__namespace.default.createElement(Link2__default.default, {
32238
32340
  href: activeCategoryId ? vendorProductCreateUrl(activeCategoryId, {
@@ -32243,34 +32345,32 @@ function VendorCategoryWorkspacePage() {
32243
32345
  }
32244
32346
  }))));
32245
32347
  }
32246
- var CATEGORY_PRODUCT_HIDDEN_FIELDS, CATEGORY_PRODUCT_EXTRA_COLUMNS;
32348
+ var CATEGORY_PRODUCT_HIDDEN_FIELDS, VENDOR_EXTRA_COLUMN, EVENT_EXTRA_COLUMN;
32247
32349
  var init_VendorCategoryWorkspacePage = __esm({
32248
32350
  "src/admin/pages/VendorCategoryWorkspacePage.tsx"() {
32249
32351
  "use client";
32250
32352
  init_vendor_scope();
32251
32353
  init_CRUD();
32252
32354
  init_store_crud_configs();
32355
+ init_admin_config_context();
32253
32356
  init_use_catalog_categories();
32254
32357
  init_category_item_label();
32255
32358
  CATEGORY_PRODUCT_HIDDEN_FIELDS = /* @__PURE__ */ new Set([
32256
32359
  "categoryId"
32257
32360
  ]);
32258
- CATEGORY_PRODUCT_EXTRA_COLUMNS = [
32259
- {
32260
- field: "vendorId",
32261
- displayName: "Vendor",
32262
- relationApi: "/api/vendors",
32263
- relationLabelField: "name",
32264
- relationValueField: "id"
32265
- },
32266
- {
32267
- field: "eventName",
32268
- displayName: "Event"
32269
- }
32270
- ];
32361
+ VENDOR_EXTRA_COLUMN = {
32362
+ field: "vendorId",
32363
+ displayName: "Vendor",
32364
+ relationApi: "/api/vendors",
32365
+ relationLabelField: "name",
32366
+ relationValueField: "id"
32367
+ };
32368
+ EVENT_EXTRA_COLUMN = {
32369
+ field: "eventName",
32370
+ displayName: "Event"
32371
+ };
32271
32372
  __name(buildAdminProductColumns, "buildAdminProductColumns");
32272
- __name(buildAdminAllProductColumns, "buildAdminAllProductColumns");
32273
- __name(buildVendorProductColumns, "buildVendorProductColumns");
32373
+ __name(buildAllProductColumns, "buildAllProductColumns");
32274
32374
  __name(withCollectionRelationApi, "withCollectionRelationApi");
32275
32375
  __name(VendorCategoryWorkspacePage, "VendorCategoryWorkspacePage");
32276
32376
  }
@@ -32285,7 +32385,52 @@ function CollectionsWorkspacePage() {
32285
32385
  const { data: session } = react.useSession();
32286
32386
  const vendorPortal = isVendorPortalUser(session?.user);
32287
32387
  const isCatalog = !vendorPortal;
32288
- const collectionColumns = React26.useMemo(() => exports.STORE_CRUD_CONFIGS.collections.columns.filter((c) => c.field !== "vendorId"), []);
32388
+ const { multiVendorEnabled } = React26.useContext(exports.AdminConfigContext);
32389
+ const [vendorOptions, setVendorOptions] = React26.useState([]);
32390
+ React26.useEffect(() => {
32391
+ if (vendorPortal || multiVendorEnabled === false) return;
32392
+ fetch("/api/vendors?limit=500").then((r) => r.ok ? r.json() : null).then((data) => {
32393
+ if (!data?.data?.length) return;
32394
+ setVendorOptions(data.data.map((v) => ({
32395
+ value: String(v.id),
32396
+ label: v.name
32397
+ })));
32398
+ }).catch(() => {
32399
+ });
32400
+ }, [
32401
+ vendorPortal,
32402
+ multiVendorEnabled
32403
+ ]);
32404
+ const showVendorColumn = multiVendorEnabled !== false && !vendorPortal;
32405
+ const collectionColumns = React26.useMemo(() => {
32406
+ const base = exports.STORE_CRUD_CONFIGS.collections.columns.filter((c) => c.field !== "vendorId");
32407
+ return showVendorColumn ? [
32408
+ VENDOR_COLUMN,
32409
+ ...base
32410
+ ] : base;
32411
+ }, [
32412
+ showVendorColumn
32413
+ ]);
32414
+ const collectionFilters = React26.useMemo(() => {
32415
+ if (!showVendorColumn || vendorOptions.length <= 1) return void 0;
32416
+ return [
32417
+ {
32418
+ param: "vendorId",
32419
+ label: "Vendor",
32420
+ type: "select",
32421
+ options: [
32422
+ {
32423
+ value: "",
32424
+ label: "All vendors"
32425
+ },
32426
+ ...vendorOptions
32427
+ ]
32428
+ }
32429
+ ];
32430
+ }, [
32431
+ showVendorColumn,
32432
+ vendorOptions
32433
+ ]);
32289
32434
  const listParams = React26.useMemo(() => isCatalog ? {
32290
32435
  isCatalog: "true"
32291
32436
  } : void 0, [
@@ -32301,20 +32446,32 @@ function CollectionsWorkspacePage() {
32301
32446
  title: "Collections",
32302
32447
  apiEndpoint: "/api/collections",
32303
32448
  columns: collectionColumns,
32304
- filterColumns: exports.STORE_CRUD_CONFIGS.collections.columns,
32449
+ filterColumns: collectionColumns,
32305
32450
  addEditPageUrl: "/admin/collections",
32306
32451
  createQueryParams,
32307
32452
  defaultSortField: "sortOrder",
32308
32453
  defaultSortOrder: "asc",
32309
- extraListParams: listParams
32454
+ extraListParams: listParams,
32455
+ filters: collectionFilters
32310
32456
  });
32311
32457
  }
32458
+ var VENDOR_COLUMN;
32312
32459
  var init_CollectionsWorkspacePage = __esm({
32313
32460
  "src/admin/pages/CollectionsWorkspacePage.tsx"() {
32314
32461
  "use client";
32315
32462
  init_vendor_scope();
32316
32463
  init_CRUD();
32317
32464
  init_store_crud_configs();
32465
+ init_admin_config_context();
32466
+ VENDOR_COLUMN = {
32467
+ field: "vendorId",
32468
+ displayName: "Vendor",
32469
+ hideInCreate: true,
32470
+ hideInEdit: true,
32471
+ relationApi: "/api/vendors",
32472
+ relationLabelField: "name",
32473
+ relationValueField: "id"
32474
+ };
32318
32475
  __name(CollectionsWorkspacePage, "CollectionsWorkspacePage");
32319
32476
  }
32320
32477
  });
@@ -36226,7 +36383,7 @@ function AdminPageResolver({ slug }) {
36226
36383
  const searchParams = navigation.useSearchParams();
36227
36384
  const { data: session } = react.useSession();
36228
36385
  const vendorPortal = isVendorPortalUser(session?.user);
36229
- const { customCrudConfigs, storeEnabled } = React26.useContext(exports.AdminConfigContext);
36386
+ const { customCrudConfigs, storeEnabled, multiVendorEnabled, eventsEnabled } = React26.useContext(exports.AdminConfigContext);
36230
36387
  const key = slug?.[0] || "dashboard";
36231
36388
  const [vendorOptions, setVendorOptions] = React26.useState([]);
36232
36389
  React26.useEffect(() => {
@@ -36252,17 +36409,21 @@ function AdminPageResolver({ slug }) {
36252
36409
  if (!config) return void 0;
36253
36410
  let columns = config.columns;
36254
36411
  let filters = config.filters ?? [];
36255
- if (vendorPortal) {
36412
+ if (vendorPortal || multiVendorEnabled === false) {
36256
36413
  columns = columns.filter((column) => column.field !== "vendorId");
36257
36414
  filters = filters.filter((filter) => filter.param !== "vendorId");
36258
36415
  }
36259
- if (!vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "product_categories" && key !== "event_products" && !columns.some((c) => c.field === "vendorId")) {
36416
+ if (eventsEnabled === false) {
36417
+ columns = columns.filter((column) => column.field !== "eventId" && column.field !== "eventName");
36418
+ filters = filters.filter((filter) => filter.param !== "eventId");
36419
+ }
36420
+ if (multiVendorEnabled !== false && !vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "event_products" && !columns.some((c) => c.field === "vendorId")) {
36260
36421
  columns = [
36261
- VENDOR_COLUMN,
36422
+ VENDOR_COLUMN2,
36262
36423
  ...columns
36263
36424
  ];
36264
36425
  }
36265
- if (!vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "product_categories" && key !== "event_products" && vendorOptions.length > 1 && !filters.some((f) => f.param === "vendorId")) {
36426
+ if (multiVendorEnabled !== false && !vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "event_products" && vendorOptions.length > 1 && !filters.some((f) => f.param === "vendorId")) {
36266
36427
  filters = [
36267
36428
  {
36268
36429
  param: "vendorId",
@@ -36291,7 +36452,9 @@ function AdminPageResolver({ slug }) {
36291
36452
  key,
36292
36453
  customCrudConfigs,
36293
36454
  vendorOptions,
36294
- vendorPortal
36455
+ vendorPortal,
36456
+ multiVendorEnabled,
36457
+ eventsEnabled
36295
36458
  ]);
36296
36459
  const isContactsWithStore = key === "contacts" && storeEnabled;
36297
36460
  const extraListParams = React26.useMemo(() => isContactsWithStore ? {
@@ -36319,6 +36482,20 @@ function AdminPageResolver({ slug }) {
36319
36482
  crud,
36320
36483
  isContactsWithStore
36321
36484
  ]);
36485
+ const isVendorRelated = React26.useMemo(() => {
36486
+ return key === "vendors" || key === "vendor-team" || key === "vendor-roles" || key === "vendor-profile" || key === "store" || key === "analytics" || key === "vendor_users" || key === "vendor_role_permissions";
36487
+ }, [
36488
+ key
36489
+ ]);
36490
+ React26.useEffect(() => {
36491
+ if (multiVendorEnabled === false && isVendorRelated) {
36492
+ router.replace("/admin/access-denied");
36493
+ }
36494
+ }, [
36495
+ multiVendorEnabled,
36496
+ isVendorRelated,
36497
+ router
36498
+ ]);
36322
36499
  React26.useEffect(() => {
36323
36500
  if (key === "layout-settings") {
36324
36501
  router.replace("/admin/settings?tab=navbar");
@@ -36336,6 +36513,34 @@ function AdminPageResolver({ slug }) {
36336
36513
  router,
36337
36514
  vendorPortal
36338
36515
  ]);
36516
+ const isEventsRelated = key === "events";
36517
+ React26.useEffect(() => {
36518
+ if (eventsEnabled === false && isEventsRelated) {
36519
+ router.replace("/admin/access-denied");
36520
+ }
36521
+ }, [
36522
+ eventsEnabled,
36523
+ isEventsRelated,
36524
+ router
36525
+ ]);
36526
+ if (multiVendorEnabled === false && isVendorRelated) {
36527
+ return /* @__PURE__ */ React26__namespace.default.createElement("div", {
36528
+ className: "flex justify-center py-8"
36529
+ }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
36530
+ className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
36531
+ }), /* @__PURE__ */ React26__namespace.default.createElement("span", {
36532
+ className: "ml-2"
36533
+ }, "Redirecting\u2026"));
36534
+ }
36535
+ if (eventsEnabled === false && isEventsRelated) {
36536
+ return /* @__PURE__ */ React26__namespace.default.createElement("div", {
36537
+ className: "flex justify-center py-8"
36538
+ }, /* @__PURE__ */ React26__namespace.default.createElement("div", {
36539
+ className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
36540
+ }), /* @__PURE__ */ React26__namespace.default.createElement("span", {
36541
+ className: "ml-2"
36542
+ }, "Redirecting\u2026"));
36543
+ }
36339
36544
  if (key === "layout-settings") {
36340
36545
  return /* @__PURE__ */ React26__namespace.default.createElement("div", {
36341
36546
  className: "flex justify-center py-8"
@@ -36632,7 +36837,7 @@ function AdminPageResolver({ slug }) {
36632
36837
  className: "text-gray-500"
36633
36838
  }, "Page not found"));
36634
36839
  }
36635
- var VendorAnalyticsPage2, DashboardPage2, SignInPage, ForgotPasswordPage2, ResetPasswordPage2, InvitePage2, SettingsPage2, AdminProfilePage2, PluginsPage2, RolesPage2, BlogGeneratorPage2, SchedulesPage2, VendorTeamPage2, VendorRolesPage2, VendorPortalProfilePage2, SubmissionDetailPage2, OrderDetailPage2, OrderPlacementPage2, OrderProductFramePage2, PaymentDetailPage2, MediaLibraryPage2, PageBuilderPage2, BrandEditPage2, ProductEditPage2, CollectionEditPage2, EventEditPage2, ComboEditPage2, VendorEditPage2, VendorsListPage2, VendorStorePage2, VendorCategoryWorkspacePage2, CollectionsWorkspacePage2, DiscountDetailPage2, DiscountEditPage2, ContactDetailPage2, BlogEditorPage, FormBuilder2, PolicyPage2, PAGE_MAP, CRUD_CONFIGS, VENDOR_COLUMN, STORE_VENDOR_RESOURCES;
36840
+ var VendorAnalyticsPage2, DashboardPage2, SignInPage, ForgotPasswordPage2, ResetPasswordPage2, InvitePage2, SettingsPage2, AdminProfilePage2, PluginsPage2, RolesPage2, BlogGeneratorPage2, SchedulesPage2, VendorTeamPage2, VendorRolesPage2, VendorPortalProfilePage2, SubmissionDetailPage2, OrderDetailPage2, OrderPlacementPage2, OrderProductFramePage2, PaymentDetailPage2, MediaLibraryPage2, PageBuilderPage2, BrandEditPage2, ProductEditPage2, CollectionEditPage2, EventEditPage2, ComboEditPage2, VendorEditPage2, VendorsListPage2, VendorStorePage2, VendorCategoryWorkspacePage2, CollectionsWorkspacePage2, DiscountDetailPage2, DiscountEditPage2, ContactDetailPage2, BlogEditorPage, FormBuilder2, PolicyPage2, PAGE_MAP, CRUD_CONFIGS, VENDOR_COLUMN2, STORE_VENDOR_RESOURCES;
36636
36841
  var init_AdminPageResolver = __esm({
36637
36842
  "src/admin/pages/AdminPageResolver.tsx"() {
36638
36843
  "use client";
@@ -36965,7 +37170,7 @@ var init_AdminPageResolver = __esm({
36965
37170
  }
36966
37171
  };
36967
37172
  __name(BlogEditorWrapper, "BlogEditorWrapper");
36968
- VENDOR_COLUMN = {
37173
+ VENDOR_COLUMN2 = {
36969
37174
  field: "vendorId",
36970
37175
  displayName: "Vendor",
36971
37176
  hideInCreate: true,
@@ -37211,21 +37416,21 @@ function EventDetailPage({ eventId }) {
37211
37416
  }, /* @__PURE__ */ React.createElement("dl", {
37212
37417
  className: "grid gap-4 sm:grid-cols-2"
37213
37418
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37214
- className: labelCls8
37419
+ className: labelCls7
37215
37420
  }, "Name"), /* @__PURE__ */ React.createElement("dd", {
37216
37421
  className: valueCls
37217
37422
  }, displayValue(event.name))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37218
- className: labelCls8
37423
+ className: labelCls7
37219
37424
  }, "Slug"), /* @__PURE__ */ React.createElement("dd", {
37220
37425
  className: valueCls
37221
37426
  }, displayValue(event.slug))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37222
- className: labelCls8
37427
+ className: labelCls7
37223
37428
  }, "Sort order"), /* @__PURE__ */ React.createElement("dd", {
37224
37429
  className: valueCls
37225
37430
  }, event.sortOrder)), /* @__PURE__ */ React.createElement("div", {
37226
37431
  className: "sm:col-span-2"
37227
37432
  }, /* @__PURE__ */ React.createElement("dt", {
37228
- className: labelCls8
37433
+ className: labelCls7
37229
37434
  }, "Description"), /* @__PURE__ */ React.createElement("dd", {
37230
37435
  className: `${valueCls} prose prose-sm max-w-none`,
37231
37436
  dangerouslySetInnerHTML: {
@@ -37234,11 +37439,11 @@ function EventDetailPage({ eventId }) {
37234
37439
  })), /* @__PURE__ */ React.createElement("div", {
37235
37440
  className: "sm:col-span-2"
37236
37441
  }, /* @__PURE__ */ React.createElement("dt", {
37237
- className: labelCls8
37442
+ className: labelCls7
37238
37443
  }, "Entity types"), /* @__PURE__ */ React.createElement("dd", {
37239
37444
  className: valueCls
37240
37445
  }, event.entityTypes?.length ? event.entityTypes.map(formatEventEntityTypeLabel).join(", ") : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37241
- className: labelCls8
37446
+ className: labelCls7
37242
37447
  }, "Banner image"), /* @__PURE__ */ React.createElement("dd", {
37243
37448
  className: valueCls
37244
37449
  }, event.bannerImageUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37247,7 +37452,7 @@ function EventDetailPage({ eventId }) {
37247
37452
  rel: "noreferrer",
37248
37453
  className: "text-blue-600 hover:underline break-all"
37249
37454
  }, event.bannerImageUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37250
- className: labelCls8
37455
+ className: labelCls7
37251
37456
  }, "Logo"), /* @__PURE__ */ React.createElement("dd", {
37252
37457
  className: valueCls
37253
37458
  }, event.logoUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37256,11 +37461,11 @@ function EventDetailPage({ eventId }) {
37256
37461
  rel: "noreferrer",
37257
37462
  className: "text-blue-600 hover:underline break-all"
37258
37463
  }, event.logoUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37259
- className: labelCls8
37464
+ className: labelCls7
37260
37465
  }, "Pricing type"), /* @__PURE__ */ React.createElement("dd", {
37261
37466
  className: valueCls
37262
37467
  }, event.pricingType ? event.pricingType.charAt(0).toUpperCase() + event.pricingType.slice(1) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37263
- className: labelCls8
37468
+ className: labelCls7
37264
37469
  }, "Mode"), /* @__PURE__ */ React.createElement("dd", {
37265
37470
  className: valueCls
37266
37471
  }, formatMode(event.entityMode))))) : activeTab === "venue" ? /* @__PURE__ */ React.createElement("section", {
@@ -37270,21 +37475,21 @@ function EventDetailPage({ eventId }) {
37270
37475
  }, /* @__PURE__ */ React.createElement("div", {
37271
37476
  className: "sm:col-span-2"
37272
37477
  }, /* @__PURE__ */ React.createElement("dt", {
37273
- className: labelCls8
37478
+ className: labelCls7
37274
37479
  }, "Venue"), /* @__PURE__ */ React.createElement("dd", {
37275
37480
  className: valueCls
37276
37481
  }, displayValue(event.venue))), event.additionalVenueDetails ? /* @__PURE__ */ React.createElement("div", {
37277
37482
  className: "sm:col-span-2"
37278
37483
  }, /* @__PURE__ */ React.createElement("dt", {
37279
- className: labelCls8
37484
+ className: labelCls7
37280
37485
  }, "Additional venue details"), /* @__PURE__ */ React.createElement("dd", {
37281
37486
  className: `${valueCls} whitespace-pre-wrap`
37282
37487
  }, event.additionalVenueDetails)) : null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37283
- className: labelCls8
37488
+ className: labelCls7
37284
37489
  }, "City"), /* @__PURE__ */ React.createElement("dd", {
37285
37490
  className: valueCls
37286
37491
  }, displayValue(event.city ?? event.cityCountry?.split(",")[0]?.trim()))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37287
- className: labelCls8
37492
+ className: labelCls7
37288
37493
  }, "Country"), /* @__PURE__ */ React.createElement("dd", {
37289
37494
  className: valueCls
37290
37495
  }, displayValue(event.country ?? (event.cityCountry?.includes(",") ? event.cityCountry.split(",").slice(1).join(",").trim() : null)))))) : activeTab === "datetime" ? /* @__PURE__ */ React.createElement("section", {
@@ -37292,29 +37497,29 @@ function EventDetailPage({ eventId }) {
37292
37497
  }, /* @__PURE__ */ React.createElement("dl", {
37293
37498
  className: "grid gap-4 sm:grid-cols-2"
37294
37499
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37295
- className: labelCls8
37500
+ className: labelCls7
37296
37501
  }, "Timezone"), /* @__PURE__ */ React.createElement("dd", {
37297
37502
  className: valueCls
37298
37503
  }, displayValue(event.timezone))), /* @__PURE__ */ React.createElement("div", null), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37299
- className: labelCls8
37504
+ className: labelCls7
37300
37505
  }, "Event start"), /* @__PURE__ */ React.createElement("dd", {
37301
37506
  className: valueCls
37302
37507
  }, event.startDate ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, startFormatted.dateLine), startFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37303
37508
  className: "text-gray-600"
37304
37509
  }, startFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37305
- className: labelCls8
37510
+ className: labelCls7
37306
37511
  }, "Event end"), /* @__PURE__ */ React.createElement("dd", {
37307
37512
  className: valueCls
37308
37513
  }, event.endDate ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, endFormatted.dateLine), endFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37309
37514
  className: "text-gray-600"
37310
37515
  }, endFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37311
- className: labelCls8
37516
+ className: labelCls7
37312
37517
  }, "Registration opens"), /* @__PURE__ */ React.createElement("dd", {
37313
37518
  className: valueCls
37314
37519
  }, event.registrationOpensAt ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, regOpensFormatted.dateLine), regOpensFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37315
37520
  className: "text-gray-600"
37316
37521
  }, regOpensFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37317
- className: labelCls8
37522
+ className: labelCls7
37318
37523
  }, "Registration closes"), /* @__PURE__ */ React.createElement("dd", {
37319
37524
  className: valueCls
37320
37525
  }, event.registrationClosesAt ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, regClosesFormatted.dateLine), regClosesFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
@@ -37328,15 +37533,15 @@ function EventDetailPage({ eventId }) {
37328
37533
  }, "Checkout & website"), /* @__PURE__ */ React.createElement("dl", {
37329
37534
  className: "grid gap-4 sm:grid-cols-2"
37330
37535
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37331
- className: labelCls8
37536
+ className: labelCls7
37332
37537
  }, "Default currency"), /* @__PURE__ */ React.createElement("dd", {
37333
37538
  className: valueCls
37334
37539
  }, displayValue(event.defaultCurrency))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37335
- className: labelCls8
37540
+ className: labelCls7
37336
37541
  }, "Supported currencies"), /* @__PURE__ */ React.createElement("dd", {
37337
37542
  className: valueCls
37338
37543
  }, event.supportedCurrencies?.length ? event.supportedCurrencies.join(", ") : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37339
- className: labelCls8
37544
+ className: labelCls7
37340
37545
  }, "Website"), /* @__PURE__ */ React.createElement("dd", {
37341
37546
  className: valueCls
37342
37547
  }, event.officialWebsiteUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37345,13 +37550,13 @@ function EventDetailPage({ eventId }) {
37345
37550
  rel: "noreferrer",
37346
37551
  className: "text-blue-600 hover:underline break-all"
37347
37552
  }, event.officialWebsiteUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37348
- className: labelCls8
37553
+ className: labelCls7
37349
37554
  }, "Support contact"), /* @__PURE__ */ React.createElement("dd", {
37350
37555
  className: valueCls
37351
37556
  }, displayValue(event.supportContact))), /* @__PURE__ */ React.createElement("div", {
37352
37557
  className: "sm:col-span-2"
37353
37558
  }, /* @__PURE__ */ React.createElement("dt", {
37354
- className: labelCls8
37559
+ className: labelCls7
37355
37560
  }, "Contact form"), /* @__PURE__ */ React.createElement("dd", {
37356
37561
  className: valueCls
37357
37562
  }, event.contactFormId != null ? /* @__PURE__ */ React.createElement(Link2__default.default, {
@@ -37360,7 +37565,7 @@ function EventDetailPage({ eventId }) {
37360
37565
  }, contactFormLabel ?? `Form #${event.contactFormId}`) : "\u2014")), /* @__PURE__ */ React.createElement("div", {
37361
37566
  className: "sm:col-span-2 grid gap-4 sm:grid-cols-2 sm:items-end"
37362
37567
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37363
- className: labelCls8
37568
+ className: labelCls7
37364
37569
  }, "Max group quantity"), /* @__PURE__ */ React.createElement("dd", {
37365
37570
  className: valueCls
37366
37571
  }, event.maxGroupPurchaseQuantity != null ? event.maxGroupPurchaseQuantity : "\u2014")), /* @__PURE__ */ React.createElement("div", {
@@ -37369,13 +37574,7 @@ function EventDetailPage({ eventId }) {
37369
37574
  className: valueCls
37370
37575
  }, event.allowGroupOrders ? "Group orders allowed" : "Group orders disabled"), /* @__PURE__ */ React.createElement("dd", {
37371
37576
  className: valueCls
37372
- }, event.sendIndividualTicketPDFToAttendees ? "Individual ticket PDFs sent to attendees" : "Individual ticket PDFs not sent"))), /* @__PURE__ */ React.createElement("div", {
37373
- className: "sm:col-span-2"
37374
- }, /* @__PURE__ */ React.createElement("dd", {
37375
- className: valueCls
37376
- }, /* @__PURE__ */ React.createElement(EventNotificationSummary, {
37377
- eventId: String(event.id)
37378
- }))))), event.socialMediaLinks && Object.keys(event.socialMediaLinks).length > 0 ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
37577
+ }, event.sendIndividualTicketPDFToAttendees ? "Individual ticket PDFs sent to attendees" : "Individual ticket PDFs not sent"))))), event.socialMediaLinks && Object.keys(event.socialMediaLinks).length > 0 ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
37379
37578
  className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3"
37380
37579
  }, "Social media"), /* @__PURE__ */ React.createElement(SocialMediaLinksDisplay, {
37381
37580
  links: event.socialMediaLinks,
@@ -37387,7 +37586,7 @@ function EventDetailPage({ eventId }) {
37387
37586
  }))
37388
37587
  }));
37389
37588
  }
37390
- var sectionCls7, labelCls8, valueCls;
37589
+ var sectionCls7, labelCls7, valueCls;
37391
37590
  var init_EventDetailPage = __esm({
37392
37591
  "src/admin/pages/EventDetailPage.tsx"() {
37393
37592
  "use client";
@@ -37399,9 +37598,8 @@ var init_EventDetailPage = __esm({
37399
37598
  init_DetailPageLayout();
37400
37599
  init_DetailPageHeader();
37401
37600
  init_EventProductsSection();
37402
- init_EventNotificationSettings();
37403
37601
  sectionCls7 = "border border-gray-200 rounded-lg p-4 bg-gray-50/50";
37404
- labelCls8 = "text-xs font-medium text-gray-500";
37602
+ labelCls7 = "text-xs font-medium text-gray-500";
37405
37603
  valueCls = "text-sm text-gray-900 mt-0.5";
37406
37604
  __name(displayValue, "displayValue");
37407
37605
  __name(formatMode, "formatMode");