@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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { useSession, signIn, signOut } from 'next-auth/react';
2
+ import { useSession, signOut, signIn } from 'next-auth/react';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import * as React26 from 'react';
@@ -10,7 +10,7 @@ import { Slot } from '@radix-ui/react-slot';
10
10
  import { cva } from 'class-variance-authority';
11
11
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
12
12
  import * as LucideIcons from 'lucide-react';
13
- import { ChevronDown, User, Settings, LogOut, LayoutDashboard, FolderTree, Store, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, FileText, Shield, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Save, Check, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Mail, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Send, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, Bell, QrCode, Car, Circle, DollarSign, Hash, ChevronLeft, Share2, Smartphone, HardDrive, Folder, Film } from 'lucide-react';
13
+ import { ChevronDown, User, Settings, LogOut, LayoutDashboard, Store, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, FileText, Shield, Puzzle, X, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Save, Check, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, Loader2, CalendarClock, Rss, ArrowLeft, Pencil, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, CheckCircle2, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, XCircle, Clock, Play, MessageCircle, Mail, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, Bell, QrCode, Car, Circle, Settings2, DollarSign, Hash, ChevronLeft, Share2, Smartphone, HardDrive, Folder, Film } from 'lucide-react';
14
14
  import Image from 'next/image';
15
15
  import Link2 from 'next/link';
16
16
  import { usePathname, useSearchParams, useRouter } from 'next/navigation';
@@ -419,7 +419,8 @@ var init_vendor_scope = __esm({
419
419
  "vendor_customers",
420
420
  "discounts",
421
421
  "events",
422
- "refund_policies"
422
+ "refund_policies",
423
+ "combos"
423
424
  ]);
424
425
  VENDOR_STORE_RBAC_ENTITIES = /* @__PURE__ */ new Set([
425
426
  ...VENDOR_SCOPED_STORE_ENTITIES,
@@ -456,7 +457,7 @@ var init_admin_config_context = __esm({
456
457
  var CMS_VERSION;
457
458
  var init_cms_version = __esm({
458
459
  "src/lib/cms-version.ts"() {
459
- CMS_VERSION = "1.0.35" ;
460
+ CMS_VERSION = "1.0.38" ;
460
461
  }
461
462
  });
462
463
  function useCatalogCategories(enabled = true) {
@@ -566,25 +567,20 @@ function AdminSidebar({ variant = "sidebar" }) {
566
567
  const sessionUser = session?.user;
567
568
  const showVendorOnboard = canOnboardVendors(sessionUser);
568
569
  const vendorPortal = isVendorPortalUser(sessionUser);
569
- const { customNavItems, customNavSections = [], storeEnabled } = useContext(AdminConfigContext);
570
+ const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled } = useContext(AdminConfigContext);
570
571
  const showStoreNav = storeEnabled || vendorPortal;
571
572
  const showPlatformNav = !vendorPortal;
572
573
  const isDrawer = variant === "drawer";
573
574
  const { categories: catalogCategories } = useCatalogCategories(showStoreNav);
574
- const activeCategoryId = searchParams.get("categoryId")?.trim() ?? "";
575
+ searchParams.get("categoryId")?.trim() ?? "";
575
576
  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/")));
576
- const vendorCatalogCategories = catalogCategories.filter((category) => category.slug !== "events");
577
+ catalogCategories.filter((category) => category.slug !== "events");
577
578
  const isActive = /* @__PURE__ */ __name((path) => {
578
579
  if (path === "/admin/dashboard") {
579
580
  return pathname === path || vendorPortal && pathname === "/admin/analytics";
580
581
  }
581
582
  return pathname.startsWith(path);
582
583
  }, "isActive");
583
- const isVendorCategoryActive = /* @__PURE__ */ __name((categoryId) => {
584
- if (!pathname.startsWith("/admin/products")) return false;
585
- if (!activeCategoryId) return false;
586
- return activeCategoryId === String(categoryId);
587
- }, "isVendorCategoryActive");
588
584
  const linkActive = "bg-gray-200 text-gray-900";
589
585
  const linkInactive = "text-gray-600 hover:bg-gray-100 hover:text-gray-900";
590
586
  const iconActive = "text-gray-700";
@@ -671,30 +667,13 @@ function AdminSidebar({ variant = "sidebar" }) {
671
667
  }, /* @__PURE__ */ React.createElement(Icon2, {
672
668
  className: `h-4 w-4 mr-2 ${isActive(item.href) ? iconActive : iconInactive}`
673
669
  }), item.label));
674
- })))), vendorCatalogCategories.length > 0 && /* @__PURE__ */ React.createElement("div", {
675
- className: sectionCls8
676
- }, /* @__PURE__ */ React.createElement("h3", {
677
- className: headingCls
678
- }, "Categories"), /* @__PURE__ */ React.createElement("ul", {
679
- className: "space-y-0.5"
680
- }, vendorCatalogCategories.map((category) => {
681
- const href = vendorCategoryWorkspaceUrl(category.id);
682
- const active = isVendorCategoryActive(category.id);
683
- return /* @__PURE__ */ React.createElement("li", {
684
- key: category.id
685
- }, /* @__PURE__ */ React.createElement(Link2, {
686
- href,
687
- className: `${linkCls} ${active ? linkActive : linkInactive}`
688
- }, /* @__PURE__ */ React.createElement(FolderTree, {
689
- className: `h-4 w-4 mr-2 ${active ? iconActive : iconInactive}`
690
- }), category.name));
691
- }))), showStoreNav && /* @__PURE__ */ React.createElement("div", {
670
+ })))), showStoreNav && /* @__PURE__ */ React.createElement("div", {
692
671
  className: sectionCls8
693
672
  }, /* @__PURE__ */ React.createElement("h3", {
694
673
  className: headingCls
695
674
  }, "Store"), /* @__PURE__ */ React.createElement("ul", {
696
675
  className: "space-y-0.5"
697
- }, showVendorOnboard && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
676
+ }, showVendorOnboard && multiVendorEnabled !== false && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
698
677
  href: "/admin/vendors",
699
678
  className: `${linkCls} ${isActive("/admin/vendors") ? linkActive : linkInactive}`
700
679
  }, /* @__PURE__ */ React.createElement(Store, {
@@ -714,12 +693,12 @@ function AdminSidebar({ variant = "sidebar" }) {
714
693
  className: `${linkCls} ${isActive("/admin/brands") ? linkActive : linkInactive}`
715
694
  }, /* @__PURE__ */ React.createElement(Building2, {
716
695
  className: `h-4 w-4 mr-2 ${isActive("/admin/brands") ? iconActive : iconInactive}`
717
- }), "Brands")), !hasCustomEventsNav ? /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
696
+ }), "Brands")), !hasCustomEventsNav && eventsEnabled !== false ? /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
718
697
  href: "/admin/events",
719
698
  className: `${linkCls} ${isActive("/admin/events") ? linkActive : linkInactive}`
720
699
  }, /* @__PURE__ */ React.createElement(CalendarDays, {
721
700
  className: `h-4 w-4 mr-2 ${isActive("/admin/events") ? iconActive : iconInactive}`
722
- }), "Events")) : null, !vendorPortal && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
701
+ }), "Events")) : null, /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
723
702
  href: "/admin/products",
724
703
  className: `${linkCls} ${isActive("/admin/products") ? linkActive : linkInactive}`
725
704
  }, /* @__PURE__ */ React.createElement(ShoppingBag, {
@@ -1147,7 +1126,7 @@ var init_builtin_plugin_descriptors = __esm({
1147
1126
  },
1148
1127
  {
1149
1128
  name: "event_notifications",
1150
- label: "Event notifications",
1129
+ label: "Notifications",
1151
1130
  version: "1.0.0",
1152
1131
  description: "Order confirmation templates with QR code and order details for events.",
1153
1132
  enabled: true,
@@ -1162,9 +1141,7 @@ var init_builtin_plugin_descriptors = __esm({
1162
1141
  function isAuthDebugClientEnabled() {
1163
1142
  if (typeof window === "undefined") return false;
1164
1143
  const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
1165
- if (v === "1" || v === "true" || v === "yes") return true;
1166
- if (v === "0" || v === "false" || v === "no") return false;
1167
- return process.env.NODE_ENV === "development";
1144
+ return v === "1" || v === "true" || v === "yes";
1168
1145
  }
1169
1146
  function logAuthClient(message, data) {
1170
1147
  if (!isAuthDebugClientEnabled()) return;
@@ -1208,13 +1185,16 @@ function useAdminViewSettings() {
1208
1185
  }
1209
1186
  function AdminLayoutInner({ children }) {
1210
1187
  const { data: session, status } = useSession();
1188
+ const { multiVendorEnabled } = useContext(AdminConfigContext);
1211
1189
  const router = useRouter();
1212
1190
  const pathname = usePathname();
1213
1191
  const [loadingTimeout, setLoadingTimeout] = useState(false);
1214
1192
  const [moreSheetOpen, setMoreSheetOpen] = useState(false);
1215
1193
  const isMobile = useIsMobile();
1194
+ const vendorBlockRedirectRef = useRef(false);
1216
1195
  useAdminViewSettings();
1217
1196
  const isPublicPath = PUBLIC_ADMIN_PATHS.includes(pathname);
1197
+ const isVendorOnlySession = session?.user?.isVendorPortal === true && session?.user?.isRBACAdmin !== true;
1218
1198
  useEffect(() => {
1219
1199
  if (isMobile) setMoreSheetOpen(false);
1220
1200
  }, [
@@ -1241,6 +1221,7 @@ function AdminLayoutInner({ children }) {
1241
1221
  return () => clearTimeout(timeout);
1242
1222
  }
1243
1223
  if (status === "unauthenticated") {
1224
+ if (vendorBlockRedirectRef.current) return;
1244
1225
  logAuthClient("AdminLayout redirect \u2192 /admin/signin (unauthenticated)", {
1245
1226
  pathname
1246
1227
  });
@@ -1254,6 +1235,29 @@ function AdminLayoutInner({ children }) {
1254
1235
  pathname,
1255
1236
  isPublicPath
1256
1237
  ]);
1238
+ useEffect(() => {
1239
+ if (isPublicPath) return;
1240
+ if (status !== "authenticated" || !session) return;
1241
+ if (!multiVendorEnabled && isVendorOnlySession) {
1242
+ vendorBlockRedirectRef.current = true;
1243
+ logAuthClient("AdminLayout: vendor session blocked (multi-vendor disabled)", {
1244
+ pathname
1245
+ });
1246
+ signOut({
1247
+ redirect: false
1248
+ }).then(() => {
1249
+ router.replace("/admin/signin?error=CredentialsSignin");
1250
+ });
1251
+ }
1252
+ }, [
1253
+ status,
1254
+ session,
1255
+ multiVendorEnabled,
1256
+ isVendorOnlySession,
1257
+ router,
1258
+ pathname,
1259
+ isPublicPath
1260
+ ]);
1257
1261
  if (isPublicPath) {
1258
1262
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AdminStyle, null), children);
1259
1263
  }
@@ -1278,6 +1282,9 @@ function AdminLayoutInner({ children }) {
1278
1282
  if (!session) {
1279
1283
  return null;
1280
1284
  }
1285
+ if (!multiVendorEnabled && isVendorOnlySession) {
1286
+ return null;
1287
+ }
1281
1288
  const isOrderProductEmbed = pathname?.includes("/admin/orders/product-frame") === true;
1282
1289
  if (isOrderProductEmbed) {
1283
1290
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(AdminStyle, null), /* @__PURE__ */ React.createElement("div", {
@@ -1349,9 +1356,48 @@ function useStoreEnabled() {
1349
1356
  currency
1350
1357
  };
1351
1358
  }
1359
+ function parseBooleanSetting(value) {
1360
+ if (typeof value === "boolean") return value;
1361
+ if (typeof value === "number") return value !== 0;
1362
+ if (typeof value === "string") {
1363
+ const normalized = value.trim().toLowerCase();
1364
+ if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") return true;
1365
+ if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") return false;
1366
+ }
1367
+ if (value && typeof value === "object") {
1368
+ const record = value;
1369
+ const nested = parseBooleanSetting(record.value ?? record.enabled ?? record.isEnabled ?? record.active ?? record.state);
1370
+ if (nested != null) return nested;
1371
+ }
1372
+ return null;
1373
+ }
1374
+ function useMultiVendorEnabled() {
1375
+ const [multiVendorEnabled, setMultiVendorEnabled] = useState(true);
1376
+ useEffect(() => {
1377
+ fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
1378
+ const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
1379
+ setMultiVendorEnabled(parsed ?? true);
1380
+ }).catch(() => {
1381
+ });
1382
+ }, []);
1383
+ return multiVendorEnabled;
1384
+ }
1385
+ function useEventsEnabled() {
1386
+ const [eventsEnabled, setEventsEnabled] = useState(true);
1387
+ useEffect(() => {
1388
+ fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
1389
+ const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
1390
+ setEventsEnabled(parsed ?? true);
1391
+ }).catch(() => {
1392
+ });
1393
+ }, []);
1394
+ return eventsEnabled;
1395
+ }
1352
1396
  function AdminLayout({ children, customNavItems = [], customNavSections = [], customCrudConfigs = {}, categoryRelatedProductLabels = {}, renderOrderDetailFooter, theme, themeRegistry, pluginDescriptors = [] }) {
1353
1397
  const resolvedTheme = useResolvedTheme(theme, themeRegistry);
1354
1398
  const { storeEnabled, currency } = useStoreEnabled();
1399
+ const multiVendorEnabled = useMultiVendorEnabled();
1400
+ const eventsEnabled = useEventsEnabled();
1355
1401
  const mergedPluginDescriptors = useMemo(() => {
1356
1402
  const seen = new Set(pluginDescriptors.map((p) => p.name));
1357
1403
  const extra = BUILTIN_PLUGIN_DESCRIPTORS.filter((p) => !seen.has(p.name));
@@ -1372,7 +1418,9 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
1372
1418
  themeRegistry,
1373
1419
  pluginDescriptors: mergedPluginDescriptors,
1374
1420
  storeEnabled,
1375
- currency
1421
+ currency,
1422
+ multiVendorEnabled,
1423
+ eventsEnabled
1376
1424
  }), [
1377
1425
  customNavItems,
1378
1426
  customNavSections,
@@ -1383,7 +1431,9 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
1383
1431
  themeRegistry,
1384
1432
  mergedPluginDescriptors,
1385
1433
  storeEnabled,
1386
- currency
1434
+ currency,
1435
+ multiVendorEnabled,
1436
+ eventsEnabled
1387
1437
  ]);
1388
1438
  return /* @__PURE__ */ React.createElement(AdminConfigContext.Provider, {
1389
1439
  value: configValue
@@ -1418,6 +1468,9 @@ var init_AdminLayout = __esm({
1418
1468
  __name(AdminLayoutInner, "AdminLayoutInner");
1419
1469
  __name(useResolvedTheme, "useResolvedTheme");
1420
1470
  __name(useStoreEnabled, "useStoreEnabled");
1471
+ __name(parseBooleanSetting, "parseBooleanSetting");
1472
+ __name(useMultiVendorEnabled, "useMultiVendorEnabled");
1473
+ __name(useEventsEnabled, "useEventsEnabled");
1421
1474
  __name(AdminLayout, "AdminLayout");
1422
1475
  }
1423
1476
  });
@@ -8695,6 +8748,14 @@ var init_SignInPage = __esm({
8695
8748
  const [error, setError] = useState("");
8696
8749
  const [loading, setLoading] = useState(false);
8697
8750
  const { status } = useSession();
8751
+ const searchParams = useSearchParams();
8752
+ useEffect(() => {
8753
+ if (searchParams.get("error")) {
8754
+ setError("Invalid email or password");
8755
+ }
8756
+ }, [
8757
+ searchParams
8758
+ ]);
8698
8759
  useEffect(() => {
8699
8760
  logAuthClient("SignInPage session status", {
8700
8761
  status
@@ -11043,8 +11104,17 @@ var init_store_crud_configs = __esm({
11043
11104
  },
11044
11105
  {
11045
11106
  param: "eventId",
11046
- label: "Event ID",
11047
- type: "text"
11107
+ label: "Event",
11108
+ type: "select",
11109
+ options: [
11110
+ {
11111
+ value: "",
11112
+ label: "All"
11113
+ }
11114
+ ],
11115
+ relationApi: "/api/events",
11116
+ relationLabelField: "name",
11117
+ relationValueField: "id"
11048
11118
  }
11049
11119
  ],
11050
11120
  columns: [
@@ -12127,6 +12197,8 @@ function SettingsPage() {
12127
12197
  });
12128
12198
  const [themeSettingsLoading, setThemeSettingsLoading] = useState(true);
12129
12199
  const [storeEnabled, setStoreEnabled] = useState(false);
12200
+ const [multiVendorEnabled, setMultiVendorEnabled] = useState(true);
12201
+ const [eventsEnabled, setEventsEnabled] = useState(true);
12130
12202
  const [storeSettingsLoading, setStoreSettingsLoading] = useState(true);
12131
12203
  const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
12132
12204
  const [currencies, setCurrencies] = useState([]);
@@ -12184,6 +12256,14 @@ function SettingsPage() {
12184
12256
  setStoreEnabled(data.enabled === "true");
12185
12257
  setCurrency(data.currency || DEFAULT_CURRENCY);
12186
12258
  }).finally(() => setStoreSettingsLoading(false));
12259
+ fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
12260
+ setMultiVendorEnabled(data.enabled !== "false");
12261
+ }).catch(() => {
12262
+ });
12263
+ fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
12264
+ setEventsEnabled(data.enabled !== "false");
12265
+ }).catch(() => {
12266
+ });
12187
12267
  fetch("/api/currencies/exchange-rates").then((r) => r.ok ? r.json() : []).then((data) => {
12188
12268
  if (data.length > 0) {
12189
12269
  setExchangeRates(data.map((entry) => ({
@@ -12300,6 +12380,30 @@ function SettingsPage() {
12300
12380
  }
12301
12381
  })
12302
12382
  });
12383
+ await fetch("/api/settings/multi_vendor", {
12384
+ method: "PUT",
12385
+ headers: {
12386
+ "Content-Type": "application/json"
12387
+ },
12388
+ body: JSON.stringify({
12389
+ enabled: {
12390
+ value: multiVendorEnabled ? "true" : "false",
12391
+ type: "public"
12392
+ }
12393
+ })
12394
+ });
12395
+ await fetch("/api/settings/events", {
12396
+ method: "PUT",
12397
+ headers: {
12398
+ "Content-Type": "application/json"
12399
+ },
12400
+ body: JSON.stringify({
12401
+ enabled: {
12402
+ value: eventsEnabled ? "true" : "false",
12403
+ type: "public"
12404
+ }
12405
+ })
12406
+ });
12303
12407
  toast.success("Store settings saved");
12304
12408
  window.location.reload();
12305
12409
  } catch {
@@ -12559,7 +12663,25 @@ function SettingsPage() {
12559
12663
  className: "text-sm font-medium text-gray-700"
12560
12664
  }, "Enable Store"), /* @__PURE__ */ React.createElement("p", {
12561
12665
  className: "text-xs text-gray-500"
12562
- }, "Shows Store section in sidebar with Products, Orders, Payments, etc.")))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
12666
+ }, "Shows Store section in sidebar with Products, Orders, Payments, etc.")))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
12667
+ className: "mt-4 flex items-center gap-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
12668
+ }, /* @__PURE__ */ React.createElement(Switch, {
12669
+ checked: multiVendorEnabled,
12670
+ onCheckedChange: setMultiVendorEnabled
12671
+ }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
12672
+ className: "text-sm font-medium text-gray-700"
12673
+ }, "Multi Vendor Support"), /* @__PURE__ */ React.createElement("p", {
12674
+ className: "text-xs text-gray-500"
12675
+ }, "Enable vendor portals, vendor logins, and vendor-scoped store data. Disabling this blocks vendor-only accounts from signing in."))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
12676
+ className: "mt-4 flex items-center gap-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
12677
+ }, /* @__PURE__ */ React.createElement(Switch, {
12678
+ checked: eventsEnabled,
12679
+ onCheckedChange: setEventsEnabled
12680
+ }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
12681
+ className: "text-sm font-medium text-gray-700"
12682
+ }, "Events"), /* @__PURE__ */ React.createElement("p", {
12683
+ className: "text-xs text-gray-500"
12684
+ }, "Enable event management. Disabling this hides the Events tab and blocks all event-related APIs."))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
12563
12685
  className: "flex items-center justify-between mb-1"
12564
12686
  }, /* @__PURE__ */ React.createElement("label", {
12565
12687
  className: "block text-sm font-semibold text-gray-700"
@@ -14147,236 +14269,774 @@ var init_email_recipients = __esm({
14147
14269
  __name(serializeEmailRecipients, "serializeEmailRecipients");
14148
14270
  }
14149
14271
  });
14150
-
14151
- // src/message-templates/event-order-defaults.ts
14152
- var EVENT_ORDER_WHATSAPP_PARAM_KEYS, EVENT_ORDER_TEMPLATE_VARIABLE_HINTS;
14153
- var init_event_order_defaults = __esm({
14154
- "src/message-templates/event-order-defaults.ts"() {
14155
- EVENT_ORDER_WHATSAPP_PARAM_KEYS = [
14156
- "customerName",
14157
- "eventName",
14272
+ function getEmailTriggerDefaults(triggerKey) {
14273
+ return EMAIL_TRIGGER_DEFAULTS[triggerKey] ?? {
14274
+ subject: "",
14275
+ body: "",
14276
+ subjectPlaceholder: "e.g. Order update for {{orderNumber}}",
14277
+ bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} has been updated."
14278
+ };
14279
+ }
14280
+ async function jsonFetch(url, init) {
14281
+ const res = await fetch(url, {
14282
+ credentials: "include",
14283
+ ...init
14284
+ });
14285
+ const data = await res.json().catch(() => ({}));
14286
+ if (!res.ok) {
14287
+ throw new Error(data?.error || `Request failed (${res.status})`);
14288
+ }
14289
+ return data;
14290
+ }
14291
+ function useOrderNotificationTriggerBindings(channel) {
14292
+ const [triggers, setTriggers] = useState([]);
14293
+ const [bindings, setBindings] = useState([]);
14294
+ const [loading, setLoading] = useState(true);
14295
+ const load = useCallback(async () => {
14296
+ setLoading(true);
14297
+ try {
14298
+ const [triggersRes, bindingsRes] = await Promise.all([
14299
+ jsonFetch("/api/order_notification_triggers?limit=100&sortField=sortOrder&sortOrder=asc"),
14300
+ // Bindings for all channels are fetched and filtered client-side rather
14301
+ // than relying on server-side ?channel= filtering, since that's not
14302
+ // confirmed to be supported by the generic CRUD layer.
14303
+ jsonFetch("/api/order_notification_bindings?limit=200")
14304
+ ]);
14305
+ setTriggers((triggersRes.data ?? []).filter((t) => t.enabled));
14306
+ setBindings((bindingsRes.data ?? []).filter((b) => b.channel === channel));
14307
+ } catch (e) {
14308
+ toast.error(e instanceof Error ? e.message : "Failed to load trigger bindings");
14309
+ } finally {
14310
+ setLoading(false);
14311
+ }
14312
+ }, [
14313
+ channel
14314
+ ]);
14315
+ useEffect(() => {
14316
+ void load();
14317
+ }, [
14318
+ load
14319
+ ]);
14320
+ const rebind = useCallback(async (triggerKey, messageTemplateId, templateLabel) => {
14321
+ const existing = bindings.find((b) => b.triggerKey === triggerKey);
14322
+ try {
14323
+ if (existing) {
14324
+ const updated = await jsonFetch(`/api/order_notification_bindings/${existing.id}`, {
14325
+ method: "PUT",
14326
+ headers: {
14327
+ "Content-Type": "application/json"
14328
+ },
14329
+ body: JSON.stringify({
14330
+ messageTemplateId
14331
+ })
14332
+ });
14333
+ setBindings((prev) => prev.map((b) => b.id === updated.id ? updated : b));
14334
+ } else {
14335
+ const created = await jsonFetch("/api/order_notification_bindings", {
14336
+ method: "POST",
14337
+ headers: {
14338
+ "Content-Type": "application/json"
14339
+ },
14340
+ body: JSON.stringify({
14341
+ triggerKey,
14342
+ channel,
14343
+ messageTemplateId,
14344
+ enabled: true
14345
+ })
14346
+ });
14347
+ setBindings((prev) => [
14348
+ ...prev,
14349
+ created
14350
+ ]);
14351
+ }
14352
+ toast.success(`"${triggerKey}" bound to "${templateLabel}"`);
14353
+ return true;
14354
+ } catch (e) {
14355
+ toast.error(e instanceof Error ? e.message : "Failed to update binding");
14356
+ return false;
14357
+ }
14358
+ }, [
14359
+ bindings,
14360
+ channel
14361
+ ]);
14362
+ return {
14363
+ triggers,
14364
+ bindings,
14365
+ loading,
14366
+ reload: load,
14367
+ rebind
14368
+ };
14369
+ }
14370
+ var KNOWN_VARS, EMAIL_TRIGGER_DEFAULTS;
14371
+ var init_order_notification_bindings_shared = __esm({
14372
+ "src/admin/components/order-notification-bindings-shared.ts"() {
14373
+ "use client";
14374
+ KNOWN_VARS = [
14375
+ "orderId",
14158
14376
  "orderNumber",
14159
- "orderTotal",
14377
+ "customerName",
14378
+ "customerPhone",
14379
+ "total",
14160
14380
  "currency",
14161
- "venue",
14162
- "startDate",
14163
- "trackUrl"
14381
+ "vendorId",
14382
+ "refundAmount"
14164
14383
  ];
14165
- EVENT_ORDER_TEMPLATE_VARIABLE_HINTS = {
14166
- eventName: "Event title",
14167
- eventSlug: "Event URL slug",
14168
- venue: "Venue name",
14169
- startDate: "Formatted event start",
14170
- orderNumber: "Order number",
14171
- orderTotal: "Order total amount",
14172
- currency: "Currency code",
14173
- customerName: "Buyer name",
14174
- customerEmail: "Buyer email",
14175
- customerPhone: "Buyer phone",
14176
- productNames: "Comma-separated ticket names",
14177
- trackUrl: "Public order tracking link (QR destination)",
14178
- qrImageUrl: 'QR code image URL for email (use in <img src="\u2026">)',
14179
- orderDetails: "Plain-text order summary with line items",
14180
- orderDetailsHtml: "HTML order summary block",
14181
- trackUrlWhatsApp: "Same as trackUrl \u2014 include in Meta template as last param"
14384
+ EMAIL_TRIGGER_DEFAULTS = {
14385
+ order_placed: {
14386
+ subject: "Your order {{orderNumber}} is confirmed",
14387
+ subjectPlaceholder: "e.g. Your order {{orderNumber}} is confirmed",
14388
+ body: `Hi {{customerName}},
14389
+
14390
+ Thank you for your order! Your order {{orderNumber}} for {{total}} {{currency}} has been confirmed.
14391
+
14392
+ We'll keep you updated on any changes.
14393
+
14394
+ Thank you!`,
14395
+ bodyPlaceholder: "Hi {{customerName}},\n\nYour order {{orderNumber}} for {{total}} {{currency}} is confirmed.\n\nThank you!"
14396
+ },
14397
+ order_cancelled: {
14398
+ subject: "Your order {{orderNumber}} has been cancelled",
14399
+ subjectPlaceholder: "e.g. Your order {{orderNumber}} has been cancelled",
14400
+ body: `Hi {{customerName}},
14401
+
14402
+ Your order {{orderNumber}} for {{total}} {{currency}} has been cancelled.
14403
+
14404
+ If a refund is due, you will receive {{refundAmount}} {{currency}} back to your original payment method.
14405
+
14406
+ If you have any questions, please contact us.
14407
+
14408
+ Thank you!`,
14409
+ 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."
14410
+ }
14182
14411
  };
14412
+ __name(getEmailTriggerDefaults, "getEmailTriggerDefaults");
14413
+ __name(jsonFetch, "jsonFetch");
14414
+ __name(useOrderNotificationTriggerBindings, "useOrderNotificationTriggerBindings");
14183
14415
  }
14184
14416
  });
14185
- function mergeChannelUpdate(allItems, channel, updatedChannelItems) {
14186
- return [
14187
- ...allItems.filter((item) => item.channel !== channel),
14188
- ...updatedChannelItems
14189
- ];
14417
+ function varCount(t) {
14418
+ const explicit = t.providerMeta?.variableCount;
14419
+ if (typeof explicit === "number") return explicit;
14420
+ const matches = t.body.match(/\{\{\d+\}\}/g);
14421
+ return matches ? new Set(matches).size : 0;
14190
14422
  }
14191
- function EventOrderGlobalTemplates({ items, onChange, channel, settingsGroup = "notifications" }) {
14192
- const [templateVariables, setTemplateVariables] = useState([]);
14193
- const copy = CHANNEL_COPY[channel];
14194
- const visibleItems = useMemo(() => items.filter((item) => item.channel === channel), [
14195
- items,
14196
- channel
14423
+ function bodyExample(t) {
14424
+ const body = t.providerMeta?.components?.find((c) => c.type === "BODY");
14425
+ return body?.example?.body_text?.[0] ?? [];
14426
+ }
14427
+ function guessFromContext(context) {
14428
+ const c = context.toLowerCase();
14429
+ for (const { pattern, var: v } of CONTEXT_HINTS) {
14430
+ if (pattern.test(c)) return v;
14431
+ }
14432
+ return "";
14433
+ }
14434
+ function guessFromExampleShape(example) {
14435
+ const v = example.trim();
14436
+ if (!v) return "";
14437
+ if (/^\+?\d{10,15}$/.test(v)) return "customerPhone";
14438
+ if (/^[A-Z]{3}$/.test(v)) return "currency";
14439
+ if (/^[A-Za-z]{1,4}-?\d{2,}$/.test(v) || /^#?\d{3,}$/.test(v)) return "orderNumber";
14440
+ if (/^\d+(\.\d{1,2})?$/.test(v)) return "total";
14441
+ if (/^[A-Za-z]+(\s[A-Za-z]+)?$/.test(v) && v.length <= 30) return "customerName";
14442
+ return "";
14443
+ }
14444
+ function guessKnownVar(context, example, used) {
14445
+ const candidates = [
14446
+ guessFromContext(context),
14447
+ guessFromExampleShape(example)
14448
+ ].filter((v) => Boolean(v));
14449
+ for (const c of candidates) {
14450
+ if (!used.has(c)) return c;
14451
+ }
14452
+ return "";
14453
+ }
14454
+ function contextBeforePlaceholder(bodyText, n) {
14455
+ const marker = `{{${n}}}`;
14456
+ const idx = bodyText.indexOf(marker);
14457
+ if (idx === -1) return "";
14458
+ return bodyText.slice(Math.max(0, idx - 25), idx);
14459
+ }
14460
+ function WhatsAppTriggerBindings() {
14461
+ const { triggers, bindings, loading, reload, rebind } = useOrderNotificationTriggerBindings("whatsapp");
14462
+ const [templates, setTemplates] = useState([]);
14463
+ const [templatesLoaded, setTemplatesLoaded] = useState(false);
14464
+ const [syncing, setSyncing] = useState(false);
14465
+ const [editingTemplateId, setEditingTemplateId] = useState(null);
14466
+ const templatesById = useMemo(() => {
14467
+ const m = /* @__PURE__ */ new Map();
14468
+ for (const t of templates) m.set(t.id, t);
14469
+ return m;
14470
+ }, [
14471
+ templates
14197
14472
  ]);
14198
- const displayVariables = useMemo(() => {
14199
- if (channel === "email") return EMAIL_VARIABLES;
14200
- return [
14201
- ...EVENT_ORDER_WHATSAPP_PARAM_KEYS
14473
+ const loadTemplates = /* @__PURE__ */ __name(async () => {
14474
+ try {
14475
+ const res = await jsonFetch("/api/message-templates/whatsapp");
14476
+ setTemplates(res.items ?? []);
14477
+ } catch (e) {
14478
+ toast.error(e instanceof Error ? e.message : "Failed to load WhatsApp templates");
14479
+ } finally {
14480
+ setTemplatesLoaded(true);
14481
+ }
14482
+ }, "loadTemplates");
14483
+ useMemo(() => {
14484
+ if (!templatesLoaded) void loadTemplates();
14485
+ }, [
14486
+ templatesLoaded
14487
+ ]);
14488
+ const handleSync = /* @__PURE__ */ __name(async () => {
14489
+ setSyncing(true);
14490
+ try {
14491
+ await jsonFetch("/api/message-templates/whatsapp/sync", {
14492
+ method: "POST"
14493
+ });
14494
+ await Promise.all([
14495
+ loadTemplates(),
14496
+ reload()
14497
+ ]);
14498
+ toast.success("Synced templates from Meta");
14499
+ } catch (e) {
14500
+ toast.error(e instanceof Error ? e.message : "Sync failed");
14501
+ } finally {
14502
+ setSyncing(false);
14503
+ }
14504
+ }, "handleSync");
14505
+ const handleRebind = /* @__PURE__ */ __name(async (triggerKey, messageTemplateId) => {
14506
+ const label = templatesById.get(messageTemplateId)?.name ?? String(messageTemplateId);
14507
+ await rebind(triggerKey, messageTemplateId, label);
14508
+ }, "handleRebind");
14509
+ const handleSaveParamOrder = /* @__PURE__ */ __name(async (templateId, paramOrder) => {
14510
+ try {
14511
+ const res = await jsonFetch(`/api/message-templates/whatsapp/${templateId}`, {
14512
+ method: "PATCH",
14513
+ headers: {
14514
+ "Content-Type": "application/json"
14515
+ },
14516
+ body: JSON.stringify({
14517
+ paramOrder
14518
+ })
14519
+ });
14520
+ setTemplates((prev) => prev.map((t) => t.id === res.item.id ? res.item : t));
14521
+ toast.success("Param order saved");
14522
+ setEditingTemplateId(null);
14523
+ } catch (e) {
14524
+ toast.error(e instanceof Error ? e.message : "Failed to save param order");
14525
+ }
14526
+ }, "handleSaveParamOrder");
14527
+ if (loading || !templatesLoaded) {
14528
+ return /* @__PURE__ */ React.createElement("div", {
14529
+ className: "flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"
14530
+ }, /* @__PURE__ */ React.createElement(Loader2, {
14531
+ className: "h-4 w-4 animate-spin"
14532
+ }), "Loading trigger bindings\u2026");
14533
+ }
14534
+ return /* @__PURE__ */ React.createElement("div", {
14535
+ className: "space-y-3 rounded-md border border-gray-200 dark:border-gray-600 p-3"
14536
+ }, /* @__PURE__ */ React.createElement("div", {
14537
+ className: "flex items-start justify-between gap-2"
14538
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
14539
+ className: "text-sm font-medium text-gray-900 dark:text-white"
14540
+ }, "Order trigger templates"), /* @__PURE__ */ React.createElement("p", {
14541
+ className: "text-xs text-gray-500 dark:text-gray-400 mt-1"
14542
+ }, "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, {
14543
+ type: "button",
14544
+ variant: "outline",
14545
+ size: "sm",
14546
+ className: "gap-1.5 h-8 shrink-0",
14547
+ disabled: syncing,
14548
+ onClick: /* @__PURE__ */ __name(() => void handleSync(), "onClick")
14549
+ }, syncing ? /* @__PURE__ */ React.createElement(Loader2, {
14550
+ className: "h-3.5 w-3.5 animate-spin"
14551
+ }) : /* @__PURE__ */ React.createElement(RefreshCw, {
14552
+ className: "h-3.5 w-3.5"
14553
+ }), "Sync from Meta")), /* @__PURE__ */ React.createElement("div", {
14554
+ className: "space-y-3"
14555
+ }, triggers.length === 0 ? /* @__PURE__ */ React.createElement("p", {
14556
+ className: "text-xs text-amber-600 dark:text-amber-400"
14557
+ }, "No order triggers found. Run database migrations to seed default triggers.") : null, triggers.map(({ triggerKey, label, description }) => {
14558
+ const binding = bindings.find((b) => b.triggerKey === triggerKey) ?? null;
14559
+ const template = binding?.messageTemplateId != null ? templatesById.get(binding.messageTemplateId) : void 0;
14560
+ const paramOrder = template?.providerMeta?.paramOrder ?? [];
14561
+ const missingParamOrder = template && varCount(template) > 0 && paramOrder.length === 0;
14562
+ return /* @__PURE__ */ React.createElement("div", {
14563
+ key: triggerKey,
14564
+ className: "space-y-2 border-t border-gray-100 pt-3 first:border-t-0 first:pt-0 dark:border-gray-700"
14565
+ }, /* @__PURE__ */ React.createElement("div", {
14566
+ className: "flex items-center gap-2"
14567
+ }, /* @__PURE__ */ React.createElement(MessageCircle, {
14568
+ className: "h-3.5 w-3.5 text-gray-400 shrink-0"
14569
+ }), /* @__PURE__ */ React.createElement("span", {
14570
+ className: "text-sm font-medium text-gray-900 dark:text-gray-100"
14571
+ }, label), /* @__PURE__ */ React.createElement("span", {
14572
+ className: "text-[11px] font-mono text-gray-400"
14573
+ }, triggerKey)), description ? /* @__PURE__ */ React.createElement("p", {
14574
+ className: "text-[11px] text-gray-500 dark:text-gray-400"
14575
+ }, description) : null, /* @__PURE__ */ React.createElement("div", {
14576
+ className: "flex flex-wrap items-center gap-2"
14577
+ }, /* @__PURE__ */ React.createElement(Select, {
14578
+ value: binding?.messageTemplateId != null ? String(binding.messageTemplateId) : void 0,
14579
+ onValueChange: /* @__PURE__ */ __name((v) => void handleRebind(triggerKey, Number(v)), "onValueChange")
14580
+ }, /* @__PURE__ */ React.createElement(SelectTrigger, {
14581
+ className: "h-8 text-sm w-64"
14582
+ }, /* @__PURE__ */ React.createElement(SelectValue, {
14583
+ placeholder: "Select a template\u2026"
14584
+ })), /* @__PURE__ */ React.createElement(SelectContent, null, templates.map((t) => /* @__PURE__ */ React.createElement(SelectItem, {
14585
+ key: t.id,
14586
+ value: String(t.id)
14587
+ }, t.name, t.providerMeta?.status ? ` (${t.providerMeta.status})` : "")))), template ? /* @__PURE__ */ React.createElement(Button, {
14588
+ type: "button",
14589
+ variant: "ghost",
14590
+ size: "sm",
14591
+ className: "h-8 gap-1 text-xs",
14592
+ onClick: /* @__PURE__ */ __name(() => setEditingTemplateId(template.id), "onClick")
14593
+ }, /* @__PURE__ */ React.createElement(Settings2, {
14594
+ className: "h-3.5 w-3.5"
14595
+ }), paramOrder.length > 0 ? `Params: ${paramOrder.join(" \u2192 ")}` : "Set param order") : null), missingParamOrder ? /* @__PURE__ */ React.createElement("p", {
14596
+ className: "text-xs text-amber-600 dark:text-amber-400"
14597
+ }, "\u26A0 No param order set \u2014 variables may send in the wrong slots.") : null, template?.providerMeta?.language ? /* @__PURE__ */ React.createElement("p", {
14598
+ className: "text-[11px] text-gray-400"
14599
+ }, "Language: ", template.providerMeta.language) : null);
14600
+ })), editingTemplateId !== null && templatesById.get(editingTemplateId) && /* @__PURE__ */ React.createElement(ParamOrderEditor, {
14601
+ template: templatesById.get(editingTemplateId),
14602
+ onCancel: /* @__PURE__ */ __name(() => setEditingTemplateId(null), "onCancel"),
14603
+ onSave: /* @__PURE__ */ __name((order) => void handleSaveParamOrder(editingTemplateId, order), "onSave")
14604
+ }));
14605
+ }
14606
+ function ParamOrderEditor({ template, onCancel, onSave }) {
14607
+ const count = Math.max(varCount(template), template.providerMeta?.paramOrder?.length ?? 0);
14608
+ const example = bodyExample(template);
14609
+ const existing = template.providerMeta?.paramOrder ?? [];
14610
+ const bodyText = template.providerMeta?.components?.find((c) => c.type === "BODY")?.text ?? template.body;
14611
+ const initialGuesses = useMemo(() => {
14612
+ const base = Array.from({
14613
+ length: count
14614
+ }, (_, i) => existing[i] ?? "");
14615
+ const used = new Set(base.filter(Boolean));
14616
+ const auto = /* @__PURE__ */ new Set();
14617
+ const withGuesses = base.map((v, i) => {
14618
+ if (v) return v;
14619
+ const context = contextBeforePlaceholder(bodyText, i + 1);
14620
+ const guess = guessKnownVar(context, example[i] ?? "", used);
14621
+ if (guess) {
14622
+ used.add(guess);
14623
+ auto.add(i);
14624
+ return guess;
14625
+ }
14626
+ return v;
14627
+ });
14628
+ return {
14629
+ values: withGuesses,
14630
+ autoFilled: auto
14631
+ };
14632
+ }, []);
14633
+ const [values, setValues] = useState(initialGuesses.values);
14634
+ const [autoFilled, setAutoFilled] = useState(initialGuesses.autoFilled);
14635
+ const [customIndex, setCustomIndex] = useState(null);
14636
+ function setValue(i, v) {
14637
+ setValues((prev) => {
14638
+ const next = [
14639
+ ...prev
14640
+ ];
14641
+ next[i] = v;
14642
+ return next;
14643
+ });
14644
+ setAutoFilled((prev) => {
14645
+ if (!prev.has(i)) return prev;
14646
+ const next = new Set(prev);
14647
+ next.delete(i);
14648
+ return next;
14649
+ });
14650
+ }
14651
+ __name(setValue, "setValue");
14652
+ const allFilled = values.length > 0 && values.every((v) => v.trim() !== "");
14653
+ return /* @__PURE__ */ React.createElement("div", {
14654
+ className: "fixed inset-0 bg-black/30 flex items-center justify-center z-50 p-4"
14655
+ }, /* @__PURE__ */ React.createElement("div", {
14656
+ 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"
14657
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
14658
+ className: "font-semibold text-gray-900 dark:text-gray-100"
14659
+ }, template.name), /* @__PURE__ */ React.createElement("p", {
14660
+ className: "text-xs text-gray-500 dark:text-gray-400 mt-1 font-mono break-words"
14661
+ }, bodyText)), count === 0 ? /* @__PURE__ */ React.createElement("p", {
14662
+ className: "text-sm text-gray-500 dark:text-gray-400"
14663
+ }, "This template has no positional variables \u2014 nothing to configure.") : /* @__PURE__ */ React.createElement("div", {
14664
+ className: "space-y-2"
14665
+ }, autoFilled.size > 0 ? /* @__PURE__ */ React.createElement("p", {
14666
+ className: "text-xs text-gray-500 dark:text-gray-400"
14667
+ }, "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({
14668
+ length: count
14669
+ }).map((_, i) => /* @__PURE__ */ React.createElement("div", {
14670
+ key: i,
14671
+ className: "flex items-center gap-2"
14672
+ }, /* @__PURE__ */ React.createElement("span", {
14673
+ className: "text-xs font-mono text-gray-400 w-10"
14674
+ }, `{{${i + 1}}}`), customIndex === i ? /* @__PURE__ */ React.createElement("input", {
14675
+ autoFocus: true,
14676
+ value: values[i],
14677
+ onChange: /* @__PURE__ */ __name((e) => setValue(i, e.target.value), "onChange"),
14678
+ onBlur: /* @__PURE__ */ __name(() => setCustomIndex(null), "onBlur"),
14679
+ placeholder: "custom variable name",
14680
+ className: "flex-1 h-8 border border-gray-300 dark:border-gray-600 rounded-md px-2 text-sm font-mono bg-transparent"
14681
+ }) : /* @__PURE__ */ React.createElement(Select, {
14682
+ value: KNOWN_VARS.includes(values[i]) ? values[i] : values[i] ? "__custom__" : void 0,
14683
+ onValueChange: /* @__PURE__ */ __name((v) => {
14684
+ if (v === "__custom__") {
14685
+ setValue(i, "");
14686
+ setCustomIndex(i);
14687
+ } else {
14688
+ setValue(i, v);
14689
+ }
14690
+ }, "onValueChange")
14691
+ }, /* @__PURE__ */ React.createElement(SelectTrigger, {
14692
+ className: "flex-1 h-8 text-sm"
14693
+ }, /* @__PURE__ */ React.createElement(SelectValue, {
14694
+ placeholder: "Select variable\u2026"
14695
+ })), /* @__PURE__ */ React.createElement(SelectContent, null, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement(SelectItem, {
14696
+ key: v,
14697
+ value: v
14698
+ }, v)), /* @__PURE__ */ React.createElement(SelectItem, {
14699
+ value: "__custom__"
14700
+ }, "Custom\u2026"))), autoFilled.has(i) ? /* @__PURE__ */ React.createElement("span", {
14701
+ className: "text-[10px] font-medium text-emerald-600 dark:text-emerald-400 shrink-0"
14702
+ }, "auto") : null, example[i] ? /* @__PURE__ */ React.createElement("span", {
14703
+ className: "text-xs text-gray-400 w-24 truncate shrink-0",
14704
+ title: example[i]
14705
+ }, "e.g. ", example[i]) : null))), /* @__PURE__ */ React.createElement("div", {
14706
+ className: "flex justify-end gap-2 pt-2"
14707
+ }, /* @__PURE__ */ React.createElement(Button, {
14708
+ type: "button",
14709
+ variant: "outline",
14710
+ size: "sm",
14711
+ onClick: onCancel
14712
+ }, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
14713
+ type: "button",
14714
+ size: "sm",
14715
+ disabled: count > 0 && !allFilled,
14716
+ onClick: /* @__PURE__ */ __name(() => onSave(values), "onClick")
14717
+ }, "Save"))));
14718
+ }
14719
+ var CONTEXT_HINTS;
14720
+ var init_whatsappTriggerBindingsPage = __esm({
14721
+ "src/admin/pages/whatsappTriggerBindingsPage.tsx"() {
14722
+ "use client";
14723
+ init_button();
14724
+ init_select();
14725
+ init_order_notification_bindings_shared();
14726
+ __name(varCount, "varCount");
14727
+ __name(bodyExample, "bodyExample");
14728
+ CONTEXT_HINTS = [
14729
+ {
14730
+ pattern: /refund/,
14731
+ var: "refundAmount"
14732
+ },
14733
+ {
14734
+ pattern: /(order\s*(no\.?|number|#|id))/,
14735
+ var: "orderNumber"
14736
+ },
14737
+ {
14738
+ pattern: /\border\b/,
14739
+ var: "orderNumber"
14740
+ },
14741
+ {
14742
+ pattern: /(phone|mobile|contact\s*number)/,
14743
+ var: "customerPhone"
14744
+ },
14745
+ {
14746
+ pattern: /(vendor|seller|store)/,
14747
+ var: "vendorId"
14748
+ },
14749
+ {
14750
+ pattern: /currency/,
14751
+ var: "currency"
14752
+ },
14753
+ {
14754
+ pattern: /(total|amount|price|pay(?:ment)?)/,
14755
+ var: "total"
14756
+ },
14757
+ {
14758
+ pattern: /(hi|hello|dear|name|customer)/,
14759
+ var: "customerName"
14760
+ }
14202
14761
  ];
14762
+ __name(guessFromContext, "guessFromContext");
14763
+ __name(guessFromExampleShape, "guessFromExampleShape");
14764
+ __name(guessKnownVar, "guessKnownVar");
14765
+ __name(contextBeforePlaceholder, "contextBeforePlaceholder");
14766
+ __name(WhatsAppTriggerBindings, "WhatsAppTriggerBindings");
14767
+ __name(ParamOrderEditor, "ParamOrderEditor");
14768
+ }
14769
+ });
14770
+ function EmailTriggerBindings() {
14771
+ const { triggers, bindings, loading, rebind } = useOrderNotificationTriggerBindings("email");
14772
+ const [templates, setTemplates] = useState([]);
14773
+ const [templatesLoaded, setTemplatesLoaded] = useState(false);
14774
+ const templatesById = useMemo(() => {
14775
+ const m = /* @__PURE__ */ new Map();
14776
+ for (const t of templates) m.set(t.id, t);
14777
+ return m;
14203
14778
  }, [
14204
- channel
14779
+ templates
14205
14780
  ]);
14206
14781
  useEffect(() => {
14207
- fetch("/api/message-templates/event-order").then((r) => r.ok ? r.json() : null).then((data) => {
14208
- if (data?.templateVariables) setTemplateVariables(data.templateVariables);
14209
- }).catch(() => void 0);
14782
+ let cancelled = false;
14783
+ (async () => {
14784
+ try {
14785
+ const res = await jsonFetch("/api/message-templates/email");
14786
+ if (!cancelled) setTemplates(res.items ?? []);
14787
+ } catch (e) {
14788
+ if (!cancelled) toast.error(e instanceof Error ? e.message : "Failed to load email templates");
14789
+ } finally {
14790
+ if (!cancelled) setTemplatesLoaded(true);
14791
+ }
14792
+ })();
14793
+ return () => {
14794
+ cancelled = true;
14795
+ };
14210
14796
  }, []);
14211
- const patchVisible = /* @__PURE__ */ __name((nextVisible) => {
14212
- onChange(mergeChannelUpdate(items, channel, nextVisible));
14213
- }, "patchVisible");
14214
- if (!visibleItems.length) return null;
14797
+ const handleTemplateSaved = /* @__PURE__ */ __name((template) => {
14798
+ setTemplates((prev) => {
14799
+ const exists = prev.some((t) => t.id === template.id);
14800
+ return exists ? prev.map((t) => t.id === template.id ? template : t) : [
14801
+ ...prev,
14802
+ template
14803
+ ].sort((a, b) => a.name.localeCompare(b.name));
14804
+ });
14805
+ }, "handleTemplateSaved");
14806
+ if (loading || !templatesLoaded) {
14807
+ return /* @__PURE__ */ React.createElement("div", {
14808
+ className: "flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400"
14809
+ }, /* @__PURE__ */ React.createElement(Loader2, {
14810
+ className: "h-4 w-4 animate-spin"
14811
+ }), "Loading trigger bindings\u2026");
14812
+ }
14215
14813
  return /* @__PURE__ */ React.createElement("div", {
14216
14814
  className: "space-y-3 rounded-md border border-gray-200 dark:border-gray-600 p-3"
14217
14815
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
14218
14816
  className: "text-sm font-medium text-gray-900 dark:text-white"
14219
- }, copy.title), /* @__PURE__ */ React.createElement("p", {
14817
+ }, "Order trigger emails"), /* @__PURE__ */ React.createElement("p", {
14220
14818
  className: "text-xs text-gray-500 dark:text-gray-400 mt-1"
14221
- }, copy.description)), /* @__PURE__ */ React.createElement("div", {
14222
- className: "rounded-md bg-gray-50 dark:bg-gray-800/50 p-2"
14223
- }, /* @__PURE__ */ React.createElement("p", {
14224
- className: "text-[11px] font-medium text-gray-600 dark:text-gray-400 mb-1"
14225
- }, "Variables"), /* @__PURE__ */ React.createElement("div", {
14226
- className: "flex flex-wrap gap-1"
14227
- }, (displayVariables.length ? displayVariables : templateVariables).map((v) => /* @__PURE__ */ React.createElement("span", {
14228
- key: v,
14229
- 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",
14230
- title: EVENT_ORDER_TEMPLATE_VARIABLE_HINTS[v] ?? v
14231
- }, `{{${v}}}`)))), visibleItems.map((t) => /* @__PURE__ */ React.createElement("div", {
14232
- key: t.channel,
14233
- className: "space-y-3 border-t border-gray-100 pt-3 dark:border-gray-700"
14819
+ }, "Write the subject and body for each trigger below. Use", " ", /* @__PURE__ */ React.createElement("code", {
14820
+ className: "text-[11px]"
14821
+ }, "{{variable}}"), " tokens \u2014 click a variable chip to insert it at your cursor.")), /* @__PURE__ */ React.createElement("div", {
14822
+ className: "space-y-4"
14823
+ }, triggers.length === 0 ? /* @__PURE__ */ React.createElement("p", {
14824
+ className: "text-xs text-amber-600 dark:text-amber-400"
14825
+ }, "No order triggers found. Run database migrations to seed default triggers.") : null, triggers.map(({ triggerKey, label, description }) => {
14826
+ const binding = bindings.find((b) => b.triggerKey === triggerKey) ?? null;
14827
+ const template = binding?.messageTemplateId != null ? templatesById.get(binding.messageTemplateId) : void 0;
14828
+ return /* @__PURE__ */ React.createElement(TriggerEmailEditor, {
14829
+ key: triggerKey,
14830
+ triggerKey,
14831
+ label,
14832
+ description,
14833
+ template,
14834
+ onSaved: handleTemplateSaved,
14835
+ onBind: /* @__PURE__ */ __name((templateId, templateLabel) => rebind(triggerKey, templateId, templateLabel), "onBind")
14836
+ });
14837
+ })));
14838
+ }
14839
+ function TriggerEmailEditor({ triggerKey, label, description, template, onSaved, onBind }) {
14840
+ const defaults = useMemo(() => getEmailTriggerDefaults(triggerKey), [
14841
+ triggerKey
14842
+ ]);
14843
+ const [subject, setSubject] = useState(() => template?.subject ?? defaults.subject);
14844
+ const [body, setBody] = useState(() => template?.body ?? defaults.body);
14845
+ const [saving, setSaving] = useState(false);
14846
+ const [focusedField, setFocusedField] = useState("body");
14847
+ const subjectRef = useRef(null);
14848
+ const bodyRef = useRef(null);
14849
+ useEffect(() => {
14850
+ if (template) {
14851
+ setSubject(template.subject ?? "");
14852
+ setBody(template.body ?? "");
14853
+ } else {
14854
+ setSubject(defaults.subject);
14855
+ setBody(defaults.body);
14856
+ }
14857
+ }, [
14858
+ template,
14859
+ defaults.subject,
14860
+ defaults.body
14861
+ ]);
14862
+ const savedSubject = template?.subject ?? defaults.subject;
14863
+ const savedBody = template?.body ?? defaults.body;
14864
+ const isDirty = subject !== savedSubject || body !== savedBody;
14865
+ function insertVariable(v) {
14866
+ const token = `{{${v}}}`;
14867
+ if (focusedField === "subject") {
14868
+ const el = subjectRef.current;
14869
+ const start = el?.selectionStart ?? subject.length;
14870
+ const end = el?.selectionEnd ?? subject.length;
14871
+ const next = subject.slice(0, start) + token + subject.slice(end);
14872
+ setSubject(next);
14873
+ requestAnimationFrame(() => {
14874
+ el?.focus();
14875
+ el?.setSelectionRange(start + token.length, start + token.length);
14876
+ });
14877
+ } else {
14878
+ const el = bodyRef.current;
14879
+ const start = el?.selectionStart ?? body.length;
14880
+ const end = el?.selectionEnd ?? body.length;
14881
+ const next = body.slice(0, start) + token + body.slice(end);
14882
+ setBody(next);
14883
+ requestAnimationFrame(() => {
14884
+ el?.focus();
14885
+ el?.setSelectionRange(start + token.length, start + token.length);
14886
+ });
14887
+ }
14888
+ }
14889
+ __name(insertVariable, "insertVariable");
14890
+ const canSave = body.trim() !== "";
14891
+ const handleSave = /* @__PURE__ */ __name(async () => {
14892
+ if (!canSave) return;
14893
+ setSaving(true);
14894
+ try {
14895
+ const templateName = template?.name ?? `${label} email`;
14896
+ let saved;
14897
+ if (template) {
14898
+ const res = await jsonFetch(`/api/message-templates/email/${template.id}`, {
14899
+ method: "PATCH",
14900
+ headers: {
14901
+ "Content-Type": "application/json"
14902
+ },
14903
+ body: JSON.stringify({
14904
+ name: templateName,
14905
+ subject,
14906
+ body
14907
+ })
14908
+ });
14909
+ saved = res.item;
14910
+ toast.success(`"${label}" email template saved`);
14911
+ } else {
14912
+ const res = await jsonFetch("/api/message-templates/email", {
14913
+ method: "POST",
14914
+ headers: {
14915
+ "Content-Type": "application/json"
14916
+ },
14917
+ body: JSON.stringify({
14918
+ name: templateName,
14919
+ subject,
14920
+ body
14921
+ })
14922
+ });
14923
+ saved = res.item;
14924
+ onSaved(saved);
14925
+ const bound = await onBind(saved.id, saved.name);
14926
+ if (!bound) {
14927
+ toast.success(`"${label}" email template created`);
14928
+ }
14929
+ return;
14930
+ }
14931
+ onSaved(saved);
14932
+ } catch (e) {
14933
+ toast.error(e instanceof Error ? e.message : "Failed to save template");
14934
+ } finally {
14935
+ setSaving(false);
14936
+ }
14937
+ }, "handleSave");
14938
+ return /* @__PURE__ */ React.createElement("div", {
14939
+ className: "space-y-3 border-t border-gray-100 pt-4 first:border-t-0 first:pt-0 dark:border-gray-700"
14234
14940
  }, /* @__PURE__ */ React.createElement("div", {
14235
- className: "flex flex-wrap items-center justify-between gap-2"
14941
+ className: "flex items-start justify-between gap-2"
14942
+ }, /* @__PURE__ */ React.createElement("div", {
14943
+ className: "min-w-0"
14236
14944
  }, /* @__PURE__ */ React.createElement("div", {
14237
- className: "text-sm font-medium"
14238
- }, t.name), /* @__PURE__ */ React.createElement("div", {
14239
14945
  className: "flex items-center gap-2"
14240
- }, /* @__PURE__ */ React.createElement(Label3, {
14241
- htmlFor: `${settingsGroup}-evt-${t.channel}-enabled`,
14242
- className: "text-xs text-gray-600"
14243
- }, "Enabled"), /* @__PURE__ */ React.createElement(Switch, {
14244
- id: `${settingsGroup}-evt-${t.channel}-enabled`,
14245
- checked: t.enabled,
14246
- onCheckedChange: /* @__PURE__ */ __name((v) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14247
- ...x,
14248
- enabled: v
14249
- } : x)), "onCheckedChange")
14250
- }))), t.channel === "email" ? /* @__PURE__ */ React.createElement("div", {
14946
+ }, /* @__PURE__ */ React.createElement(Mail, {
14947
+ className: "h-3.5 w-3.5 text-gray-400 shrink-0"
14948
+ }), /* @__PURE__ */ React.createElement("span", {
14949
+ className: "text-sm font-medium text-gray-900 dark:text-gray-100"
14950
+ }, label), /* @__PURE__ */ React.createElement("span", {
14951
+ className: "text-[11px] font-mono text-gray-400"
14952
+ }, triggerKey)), description ? /* @__PURE__ */ React.createElement("p", {
14953
+ className: "text-[11px] text-gray-500 dark:text-gray-400 mt-0.5 ml-5"
14954
+ }, description) : null), /* @__PURE__ */ React.createElement(Button, {
14955
+ type: "button",
14956
+ size: "sm",
14957
+ className: "h-8 gap-1.5 shrink-0",
14958
+ disabled: !canSave || saving || !isDirty && Boolean(template),
14959
+ onClick: /* @__PURE__ */ __name(() => void handleSave(), "onClick")
14960
+ }, saving ? /* @__PURE__ */ React.createElement(Loader2, {
14961
+ className: "h-3.5 w-3.5 animate-spin"
14962
+ }) : /* @__PURE__ */ React.createElement(Save, {
14963
+ className: "h-3.5 w-3.5"
14964
+ }), template ? "Save" : "Create")), !template ? /* @__PURE__ */ React.createElement("p", {
14965
+ className: "text-xs text-amber-600 dark:text-amber-400 ml-5"
14966
+ }, "No email saved for this trigger yet \u2014 review the draft below and click Create.") : null, /* @__PURE__ */ React.createElement("div", {
14967
+ 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"
14968
+ }, /* @__PURE__ */ React.createElement("div", {
14251
14969
  className: "space-y-1"
14252
14970
  }, /* @__PURE__ */ React.createElement(Label3, {
14253
- className: "text-xs"
14971
+ className: "text-xs text-gray-600 dark:text-gray-400"
14254
14972
  }, "Subject"), /* @__PURE__ */ React.createElement(Input, {
14255
- value: t.subject,
14256
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14257
- ...x,
14258
- subject: e.target.value
14259
- } : x)), "onChange"),
14260
- className: "h-8 text-sm"
14261
- })) : null, /* @__PURE__ */ React.createElement("div", {
14973
+ ref: subjectRef,
14974
+ value: subject,
14975
+ onChange: /* @__PURE__ */ __name((e) => setSubject(e.target.value), "onChange"),
14976
+ onFocus: /* @__PURE__ */ __name(() => setFocusedField("subject"), "onFocus"),
14977
+ placeholder: defaults.subjectPlaceholder,
14978
+ className: "h-8 text-sm bg-white dark:bg-gray-900"
14979
+ })), /* @__PURE__ */ React.createElement("div", {
14262
14980
  className: "space-y-1"
14263
14981
  }, /* @__PURE__ */ React.createElement(Label3, {
14264
- className: "text-xs"
14265
- }, t.channel === "email" ? "Body (HTML)" : "Body (reference only)"), /* @__PURE__ */ React.createElement(Textarea, {
14266
- value: t.body,
14267
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14268
- ...x,
14269
- body: e.target.value
14270
- } : x)), "onChange"),
14271
- rows: t.channel === "email" ? 8 : 3,
14272
- className: "text-sm font-mono"
14273
- })), t.channel === "whatsapp" ? /* @__PURE__ */ React.createElement("div", {
14274
- className: "space-y-1"
14982
+ className: "text-xs text-gray-600 dark:text-gray-400"
14983
+ }, "Body"), /* @__PURE__ */ React.createElement(Textarea, {
14984
+ ref: bodyRef,
14985
+ value: body,
14986
+ onChange: /* @__PURE__ */ __name((e) => setBody(e.target.value), "onChange"),
14987
+ onFocus: /* @__PURE__ */ __name(() => setFocusedField("body"), "onFocus"),
14988
+ rows: 6,
14989
+ placeholder: defaults.bodyPlaceholder,
14990
+ className: "text-sm font-mono bg-white dark:bg-gray-900 resize-y min-h-[120px]"
14991
+ })), /* @__PURE__ */ React.createElement("div", {
14992
+ className: "space-y-1.5"
14275
14993
  }, /* @__PURE__ */ React.createElement(Label3, {
14276
- className: "text-xs"
14277
- }, "Meta approved template name"), /* @__PURE__ */ React.createElement(Input, {
14278
- value: t.externalTemplateRef,
14279
- onChange: /* @__PURE__ */ __name((e) => patchVisible(visibleItems.map((x) => x.channel === t.channel ? {
14280
- ...x,
14281
- externalTemplateRef: e.target.value
14282
- } : x)), "onChange"),
14283
- placeholder: "event_order_placed",
14284
- className: "h-8 text-sm"
14285
- })) : null)));
14286
- }
14287
- async function fetchEventOrderTemplateRows() {
14288
- const res = await fetch("/api/message-templates/event-order");
14289
- if (!res.ok) return [];
14290
- const data = await res.json();
14291
- return data.items ?? [];
14292
- }
14293
- async function saveEventOrderTemplateRows(items) {
14294
- const res = await fetch("/api/message-templates/event-order", {
14295
- method: "PUT",
14296
- headers: {
14297
- "Content-Type": "application/json"
14298
- },
14299
- body: JSON.stringify({
14300
- items: items.map((t) => ({
14301
- channel: t.channel,
14302
- subject: t.subject,
14303
- body: t.body,
14304
- externalTemplateRef: t.externalTemplateRef,
14305
- enabled: t.enabled
14306
- }))
14307
- })
14308
- });
14309
- return res.ok;
14310
- }
14311
- var CHANNEL_COPY, EMAIL_VARIABLES;
14312
- var init_EventOrderGlobalTemplates = __esm({
14313
- "src/admin/components/EventOrderGlobalTemplates.tsx"() {
14994
+ className: "text-xs text-gray-500 dark:text-gray-400"
14995
+ }, "Variables \u2014 inserts into ", focusedField === "subject" ? "subject" : "body", ":"), /* @__PURE__ */ React.createElement("div", {
14996
+ className: "flex flex-wrap gap-1.5"
14997
+ }, KNOWN_VARS.map((v) => /* @__PURE__ */ React.createElement("button", {
14998
+ key: v,
14999
+ type: "button",
15000
+ title: VAR_HINTS[v],
15001
+ onClick: /* @__PURE__ */ __name(() => insertVariable(v), "onClick"),
15002
+ 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"
15003
+ }, `{{${v}}}`))), /* @__PURE__ */ React.createElement("p", {
15004
+ className: "text-[10px] text-gray-400 dark:text-gray-500"
15005
+ }, "Hover a chip to see what each variable contains at send time."))));
15006
+ }
15007
+ var VAR_HINTS;
15008
+ var init_emailTriggersBindingsPage = __esm({
15009
+ "src/admin/pages/emailTriggersBindingsPage.tsx"() {
14314
15010
  "use client";
14315
- init_label();
15011
+ init_button();
14316
15012
  init_input();
14317
15013
  init_textarea();
14318
- init_switch();
14319
- init_event_order_defaults();
14320
- CHANNEL_COPY = {
14321
- email: {
14322
- title: "Email template",
14323
- description: "HTML email with order details and QR code. Use {{qrImageUrl}} for the QR image and {{orderDetailsHtml}} for line items."
14324
- },
14325
- whatsapp: {
14326
- title: "WhatsApp template",
14327
- description: "Must match a Meta-approved template. Body params are sent in order: " + EVENT_ORDER_WHATSAPP_PARAM_KEYS.join(", ") + "."
14328
- }
15014
+ init_label();
15015
+ init_order_notification_bindings_shared();
15016
+ VAR_HINTS = {
15017
+ orderId: "Internal order ID",
15018
+ orderNumber: "Display order number",
15019
+ customerName: "Customer full name",
15020
+ customerPhone: "Customer phone",
15021
+ total: "Order total amount",
15022
+ currency: "Currency code (e.g. INR)",
15023
+ vendorId: "Vendor / store ID",
15024
+ refundAmount: "Refund amount (refund triggers)"
14329
15025
  };
14330
- EMAIL_VARIABLES = [
14331
- "customerName",
14332
- "eventName",
14333
- "orderNumber",
14334
- "orderTotal",
14335
- "currency",
14336
- "productNames",
14337
- "orderDetailsHtml",
14338
- "venue",
14339
- "startDate",
14340
- "qrImageUrl",
14341
- "trackUrl"
14342
- ];
14343
- __name(mergeChannelUpdate, "mergeChannelUpdate");
14344
- __name(EventOrderGlobalTemplates, "EventOrderGlobalTemplates");
14345
- __name(fetchEventOrderTemplateRows, "fetchEventOrderTemplateRows");
14346
- __name(saveEventOrderTemplateRows, "saveEventOrderTemplateRows");
15026
+ __name(EmailTriggerBindings, "EmailTriggerBindings");
15027
+ __name(TriggerEmailEditor, "TriggerEmailEditor");
14347
15028
  }
14348
15029
  });
14349
15030
  function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledChange, onSaveSettings, saving }) {
14350
15031
  const [tab, setTab] = useState("email");
14351
- const [templateItems, setTemplateItems] = useState([]);
14352
- const [loadingTemplates, setLoadingTemplates] = useState(true);
14353
- useEffect(() => {
14354
- let cancelled = false;
14355
- setLoadingTemplates(true);
14356
- fetchEventOrderTemplateRows().then((rows) => {
14357
- if (!cancelled) setTemplateItems(rows);
14358
- }).finally(() => {
14359
- if (!cancelled) setLoadingTemplates(false);
14360
- });
14361
- return () => {
14362
- cancelled = true;
14363
- };
14364
- }, []);
14365
- const handleSaveAll = /* @__PURE__ */ __name(async () => {
14366
- const settingsOk = await onSaveSettings();
14367
- if (!settingsOk) {
15032
+ const handleSaveEnabled = /* @__PURE__ */ __name(async () => {
15033
+ const ok = await onSaveSettings();
15034
+ if (!ok) {
14368
15035
  toast.error("Failed to save plugin settings");
14369
15036
  return;
14370
15037
  }
14371
- if (templateItems.length > 0) {
14372
- const tplOk = await saveEventOrderTemplateRows(templateItems);
14373
- if (!tplOk) {
14374
- toast.error("Failed to save notification templates");
14375
- return;
14376
- }
14377
- }
14378
- toast.success("Event notification settings saved");
14379
- }, "handleSaveAll");
15038
+ toast.success("Settings saved");
15039
+ }, "handleSaveEnabled");
14380
15040
  return /* @__PURE__ */ React.createElement("div", {
14381
15041
  className: "space-y-5"
14382
15042
  }, /* @__PURE__ */ React.createElement("div", {
@@ -14389,19 +15049,22 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
14389
15049
  className: "space-y-2 text-sm text-gray-700 dark:text-gray-300"
14390
15050
  }, /* @__PURE__ */ React.createElement("p", {
14391
15051
  className: "font-medium text-gray-900 dark:text-white"
14392
- }, "How event notifications work"), /* @__PURE__ */ React.createElement("ol", {
15052
+ }, "Order notifications"), /* @__PURE__ */ React.createElement("ol", {
14393
15053
  className: "list-decimal pl-4 space-y-1 text-xs leading-relaxed"
14394
- }, /* @__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, {
14395
- href: "/admin/events",
14396
- className: "text-blue-600 hover:underline"
14397
- }, "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", {
15054
+ }, /* @__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", {
15055
+ className: "text-[11px]"
15056
+ }, "{{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", {
15057
+ className: "text-[11px]"
15058
+ }, "order_notification_triggers"), ") and share", " ", /* @__PURE__ */ React.createElement("code", {
15059
+ className: "text-[11px]"
15060
+ }, "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", {
14398
15061
  className: "text-xs text-gray-500 dark:text-gray-400"
14399
15062
  }, "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", {
14400
15063
  className: "flex items-center justify-between gap-2"
14401
15064
  }, /* @__PURE__ */ React.createElement(Label3, {
14402
15065
  htmlFor: `${settingsGroup}-enabled`,
14403
15066
  className: "text-sm"
14404
- }, "Event notifications enabled"), /* @__PURE__ */ React.createElement(Switch, {
15067
+ }, "Order notifications enabled"), /* @__PURE__ */ React.createElement(Switch, {
14405
15068
  id: `${settingsGroup}-enabled`,
14406
15069
  checked: enabled,
14407
15070
  onCheckedChange: onEnabledChange
@@ -14421,16 +15084,9 @@ function EventNotificationsPluginSettings({ settingsGroup, enabled, onEnabledCha
14421
15084
  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"}`
14422
15085
  }, /* @__PURE__ */ React.createElement(MessageCircle, {
14423
15086
  className: "h-4 w-4"
14424
- }), "WhatsApp template"))), loadingTemplates ? /* @__PURE__ */ React.createElement("p", {
14425
- className: "text-sm text-gray-500"
14426
- }, "Loading templates\u2026") : /* @__PURE__ */ React.createElement(EventOrderGlobalTemplates, {
14427
- items: templateItems,
14428
- onChange: setTemplateItems,
14429
- channel: tab,
14430
- settingsGroup
14431
- }), /* @__PURE__ */ React.createElement(Button, {
15087
+ }), "WhatsApp template"))), tab === "whatsapp" ? /* @__PURE__ */ React.createElement(WhatsAppTriggerBindings, null) : /* @__PURE__ */ React.createElement(EmailTriggerBindings, null), /* @__PURE__ */ React.createElement(Button, {
14432
15088
  size: "sm",
14433
- onClick: /* @__PURE__ */ __name(() => void handleSaveAll(), "onClick"),
15089
+ onClick: /* @__PURE__ */ __name(() => void handleSaveEnabled(), "onClick"),
14434
15090
  disabled: saving,
14435
15091
  className: "gap-1"
14436
15092
  }, /* @__PURE__ */ React.createElement(Save, {
@@ -14443,7 +15099,8 @@ var init_EventNotificationsPluginSettings = __esm({
14443
15099
  init_button();
14444
15100
  init_label();
14445
15101
  init_switch();
14446
- init_EventOrderGlobalTemplates();
15102
+ init_whatsappTriggerBindingsPage();
15103
+ init_emailTriggersBindingsPage();
14447
15104
  __name(EventNotificationsPluginSettings, "EventNotificationsPluginSettings");
14448
15105
  }
14449
15106
  });
@@ -14823,6 +15480,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
14823
15480
  const isWhatsapp = settingsGroup === "whatsapp";
14824
15481
  const isEventNotifications = settingsGroup === "event_notifications";
14825
15482
  const isSocialMedia = settingsGroup === "social_media";
15483
+ const isMultiVendor = settingsGroup === "multi_vendor";
14826
15484
  const [enabled, setEnabled] = useState(true);
14827
15485
  const [botName, setBotName] = useState("");
14828
15486
  const [icon, setIcon] = useState("");
@@ -14903,6 +15561,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
14903
15561
  const [smsTplItems, setSmsTplItems] = useState([]);
14904
15562
  const [whatsappAccessToken, setWhatsappAccessToken] = useState("");
14905
15563
  const [whatsappPhoneNumberId, setWhatsappPhoneNumberId] = useState("");
15564
+ const [whatsappWabaId, setWhatsappWabaId] = useState("");
14906
15565
  const [whatsappHasSavedToken, setWhatsappHasSavedToken] = useState(false);
14907
15566
  const [loading, setLoading] = useState(true);
14908
15567
  const [saving, setSaving] = useState(false);
@@ -15169,6 +15828,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15169
15828
  setWhatsappAccessToken(savedToken);
15170
15829
  setWhatsappHasSavedToken(Boolean(savedToken));
15171
15830
  setWhatsappPhoneNumberId(String(data.phoneNumberId ?? data.WHATSAPP_PHONE_NUMBER_ID ?? "").trim());
15831
+ setWhatsappWabaId(String(data.wabaId ?? data.WHATSAPP_WABA_ID ?? "").trim());
15172
15832
  }
15173
15833
  if (isSocialMedia) {
15174
15834
  const savedLiToken = String(data.linkedin_access_token ?? "").trim();
@@ -15206,7 +15866,8 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15206
15866
  isSms,
15207
15867
  isWhatsapp,
15208
15868
  isEventNotifications,
15209
- isSocialMedia
15869
+ isSocialMedia,
15870
+ isMultiVendor
15210
15871
  ]);
15211
15872
  useEffect(() => {
15212
15873
  if (!isSocialMedia || loading || linkedInOrgsPrefetchedRef.current) return;
@@ -15621,6 +16282,10 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15621
16282
  phoneNumberId: {
15622
16283
  value: whatsappPhoneNumberId.trim(),
15623
16284
  type: "public"
16285
+ },
16286
+ wabaId: {
16287
+ value: whatsappWabaId.trim(),
16288
+ type: "public"
15624
16289
  }
15625
16290
  };
15626
16291
  if (whatsappAccessToken.trim()) {
@@ -15632,6 +16297,14 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
15632
16297
  }
15633
16298
  return payload2;
15634
16299
  }
16300
+ if (isMultiVendor) {
16301
+ return {
16302
+ enabled: {
16303
+ value: enabled ? "true" : "false",
16304
+ type: "public"
16305
+ }
16306
+ };
16307
+ }
15635
16308
  if (isEventNotifications) {
15636
16309
  return {
15637
16310
  enabled: {
@@ -16220,6 +16893,27 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16220
16893
  className: "h-3.5 w-3.5"
16221
16894
  }), "Save"));
16222
16895
  }
16896
+ if (isMultiVendor) {
16897
+ return /* @__PURE__ */ React.createElement("div", {
16898
+ className: "space-y-4"
16899
+ }, /* @__PURE__ */ React.createElement("div", {
16900
+ className: "flex items-center justify-between gap-2"
16901
+ }, /* @__PURE__ */ React.createElement(Label3, {
16902
+ htmlFor: `${settingsGroup}-enabled`,
16903
+ className: "text-sm"
16904
+ }, "Enabled"), /* @__PURE__ */ React.createElement(Switch, {
16905
+ id: `${settingsGroup}-enabled`,
16906
+ checked: enabled,
16907
+ onCheckedChange: setEnabled
16908
+ })), /* @__PURE__ */ React.createElement(Button, {
16909
+ size: "sm",
16910
+ onClick: handleSave,
16911
+ disabled: saving,
16912
+ className: "gap-1"
16913
+ }, /* @__PURE__ */ React.createElement(Save, {
16914
+ className: "h-3.5 w-3.5"
16915
+ }), "Save"));
16916
+ }
16223
16917
  if (isEventNotifications) {
16224
16918
  return /* @__PURE__ */ React.createElement(EventNotificationsPluginSettings, {
16225
16919
  settingsGroup,
@@ -16448,6 +17142,19 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16448
17142
  className: "h-9 text-sm"
16449
17143
  })), /* @__PURE__ */ React.createElement("div", {
16450
17144
  className: "space-y-1"
17145
+ }, /* @__PURE__ */ React.createElement(Label3, {
17146
+ htmlFor: `${settingsGroup}-wabaId`,
17147
+ className: "text-sm"
17148
+ }, "WhatsApp Business Account (WABA) ID"), /* @__PURE__ */ React.createElement(Input, {
17149
+ id: `${settingsGroup}-wabaId`,
17150
+ value: whatsappWabaId,
17151
+ onChange: /* @__PURE__ */ __name((e) => setWhatsappWabaId(e.target.value), "onChange"),
17152
+ placeholder: "From Meta Business Manager \u2192 WhatsApp Accounts",
17153
+ className: "h-9 text-sm"
17154
+ }), /* @__PURE__ */ React.createElement("p", {
17155
+ className: "text-xs text-gray-500 dark:text-gray-400"
17156
+ }, "Used to list/sync approved templates for this account \u2014 distinct from the phone number ID above.")), /* @__PURE__ */ React.createElement("div", {
17157
+ className: "space-y-1"
16451
17158
  }, /* @__PURE__ */ React.createElement(Label3, {
16452
17159
  htmlFor: `${settingsGroup}-accessToken`,
16453
17160
  className: "text-sm"
@@ -16458,9 +17165,7 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
16458
17165
  onChange: /* @__PURE__ */ __name((e) => setWhatsappAccessToken(e.target.value), "onChange"),
16459
17166
  placeholder: "Permanent or system user token",
16460
17167
  className: "h-9 text-sm"
16461
- })), /* @__PURE__ */ React.createElement("p", {
16462
- className: "text-xs text-gray-500 dark:text-gray-400"
16463
- }, "Message templates for events are configured under Plugins \u2192 Event notifications."), /* @__PURE__ */ React.createElement(Button, {
17168
+ })), /* @__PURE__ */ React.createElement(Button, {
16464
17169
  size: "sm",
16465
17170
  onClick: handleSave,
16466
17171
  disabled: saving
@@ -24138,7 +24843,7 @@ function LayoutPanelContent() {
24138
24843
  flexFill: props.flexFill ?? false
24139
24844
  };
24140
24845
  const fieldCls = "flex items-center gap-2 min-h-[28px]";
24141
- const labelCls9 = "text-[11px] text-gray-500 font-medium w-14 shrink-0";
24846
+ const labelCls8 = "text-[11px] text-gray-500 font-medium w-14 shrink-0";
24142
24847
  const inputCls9 = "h-7 text-xs flex-1 min-w-0 rounded border border-input bg-background px-2";
24143
24848
  const selectCls = "h-7 w-full text-xs rounded border border-input bg-background px-2";
24144
24849
  return /* @__PURE__ */ React26__default.createElement("div", {
@@ -24152,7 +24857,7 @@ function LayoutPanelContent() {
24152
24857
  }, /* @__PURE__ */ React26__default.createElement("div", {
24153
24858
  className: fieldCls
24154
24859
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24155
- className: labelCls9
24860
+ className: labelCls8
24156
24861
  }, "W"), /* @__PURE__ */ React26__default.createElement(Input, {
24157
24862
  value: layoutProps.width,
24158
24863
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("width", e.target.value), "onChange"),
@@ -24161,7 +24866,7 @@ function LayoutPanelContent() {
24161
24866
  })), /* @__PURE__ */ React26__default.createElement("div", {
24162
24867
  className: fieldCls
24163
24868
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24164
- className: labelCls9
24869
+ className: labelCls8
24165
24870
  }, "H"), /* @__PURE__ */ React26__default.createElement(Input, {
24166
24871
  value: layoutProps.height,
24167
24872
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("height", e.target.value), "onChange"),
@@ -24176,7 +24881,7 @@ function LayoutPanelContent() {
24176
24881
  }, /* @__PURE__ */ React26__default.createElement("div", {
24177
24882
  className: fieldCls
24178
24883
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24179
- className: labelCls9
24884
+ className: labelCls8
24180
24885
  }, "Margin"), /* @__PURE__ */ React26__default.createElement(Input, {
24181
24886
  value: layoutProps.margin,
24182
24887
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("margin", e.target.value), "onChange"),
@@ -24185,7 +24890,7 @@ function LayoutPanelContent() {
24185
24890
  })), /* @__PURE__ */ React26__default.createElement("div", {
24186
24891
  className: fieldCls
24187
24892
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24188
- className: labelCls9
24893
+ className: labelCls8
24189
24894
  }, "Padding"), /* @__PURE__ */ React26__default.createElement(Input, {
24190
24895
  value: layoutProps.padding,
24191
24896
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("padding", e.target.value), "onChange"),
@@ -24200,7 +24905,7 @@ function LayoutPanelContent() {
24200
24905
  }, /* @__PURE__ */ React26__default.createElement("div", {
24201
24906
  className: fieldCls
24202
24907
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24203
- className: labelCls9
24908
+ className: labelCls8
24204
24909
  }, "Radius"), /* @__PURE__ */ React26__default.createElement(Input, {
24205
24910
  value: layoutProps.borderRadius,
24206
24911
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("borderRadius", e.target.value), "onChange"),
@@ -24209,7 +24914,7 @@ function LayoutPanelContent() {
24209
24914
  })), /* @__PURE__ */ React26__default.createElement("div", {
24210
24915
  className: fieldCls
24211
24916
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24212
- className: labelCls9
24917
+ className: labelCls8
24213
24918
  }, "Shadow"), /* @__PURE__ */ React26__default.createElement(Input, {
24214
24919
  value: layoutProps.boxShadow,
24215
24920
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("boxShadow", e.target.value), "onChange"),
@@ -24224,7 +24929,7 @@ function LayoutPanelContent() {
24224
24929
  }, /* @__PURE__ */ React26__default.createElement("div", {
24225
24930
  className: fieldCls
24226
24931
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24227
- className: labelCls9
24932
+ className: labelCls8
24228
24933
  }, "Direction"), /* @__PURE__ */ React26__default.createElement("select", {
24229
24934
  value: layoutProps.flexDirection,
24230
24935
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("flexDirection", e.target.value), "onChange"),
@@ -24240,7 +24945,7 @@ function LayoutPanelContent() {
24240
24945
  }, "Column reverse"))), /* @__PURE__ */ React26__default.createElement("div", {
24241
24946
  className: fieldCls
24242
24947
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24243
- className: labelCls9
24948
+ className: labelCls8
24244
24949
  }, "Align"), /* @__PURE__ */ React26__default.createElement("select", {
24245
24950
  value: layoutProps.alignItems,
24246
24951
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("alignItems", e.target.value), "onChange"),
@@ -24256,7 +24961,7 @@ function LayoutPanelContent() {
24256
24961
  }, "Stretch"))), /* @__PURE__ */ React26__default.createElement("div", {
24257
24962
  className: fieldCls
24258
24963
  }, /* @__PURE__ */ React26__default.createElement(Label3, {
24259
- className: labelCls9
24964
+ className: labelCls8
24260
24965
  }, "Justify"), /* @__PURE__ */ React26__default.createElement("select", {
24261
24966
  value: layoutProps.justifyContent,
24262
24967
  onChange: /* @__PURE__ */ __name((e) => setLayoutProp("justifyContent", e.target.value), "onChange"),
@@ -25534,47 +26239,6 @@ var init_ProductIncomeCalculatorDialog = __esm({
25534
26239
  });
25535
26240
 
25536
26241
  // src/lib/currency-prices.ts
25537
- function normalizeCurrencyCode(code) {
25538
- return code.trim().toUpperCase();
25539
- }
25540
- function parseCurrencyPrices(raw) {
25541
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
25542
- const out = {};
25543
- for (const [key, value] of Object.entries(raw)) {
25544
- const code = normalizeCurrencyCode(key);
25545
- if (!code) continue;
25546
- const n = Number(value);
25547
- if (Number.isFinite(n) && n >= 0) out[code] = n;
25548
- }
25549
- return out;
25550
- }
25551
- function serializeCurrencyPrices(defaultCurrency, defaultPrice, additional) {
25552
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25553
- const out = {
25554
- [base]: defaultPrice
25555
- };
25556
- for (const [code, amount] of Object.entries(additional)) {
25557
- const normalized = normalizeCurrencyCode(code);
25558
- if (!normalized || normalized === base) continue;
25559
- if (Number.isFinite(amount) && amount >= 0) out[normalized] = amount;
25560
- }
25561
- return Object.keys(out).length ? out : null;
25562
- }
25563
- function currencyPricesToForm(defaultCurrency, storedPrice, currencyPrices) {
25564
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25565
- const map = parseCurrencyPrices(currencyPrices);
25566
- const defaultFromMap = map[base];
25567
- const defaultPrice = defaultFromMap != null ? String(defaultFromMap) : storedPrice != null && Number.isFinite(Number(storedPrice)) ? String(storedPrice) : "";
25568
- const additional = {};
25569
- for (const [code, amount] of Object.entries(map)) {
25570
- if (code === base) continue;
25571
- additional[code] = String(amount);
25572
- }
25573
- return {
25574
- defaultPrice,
25575
- additional
25576
- };
25577
- }
25578
26242
  function parseDefaultProductPrice(defaultPriceRaw) {
25579
26243
  const trimmed = defaultPriceRaw.trim();
25580
26244
  if (!trimmed) return null;
@@ -25584,31 +26248,9 @@ function parseDefaultProductPrice(defaultPriceRaw) {
25584
26248
  price: Math.round(price * 100) / 100
25585
26249
  };
25586
26250
  }
25587
- function formToCurrencyPricesPayload(defaultCurrency, defaultPriceRaw, additionalForm) {
25588
- const base = normalizeCurrencyCode(defaultCurrency) || "INR";
25589
- const defaultPrice = Number(defaultPriceRaw.trim());
25590
- if (!Number.isFinite(defaultPrice) || defaultPrice < 0) return null;
25591
- const additional = {};
25592
- for (const [code, raw] of Object.entries(additionalForm)) {
25593
- const trimmed = raw.trim();
25594
- if (!trimmed) continue;
25595
- const n = Number(trimmed);
25596
- if (!Number.isFinite(n) || n < 0) continue;
25597
- additional[normalizeCurrencyCode(code)] = n;
25598
- }
25599
- return {
25600
- price: defaultPrice,
25601
- currencyPrices: serializeCurrencyPrices(base, defaultPrice, additional)
25602
- };
25603
- }
25604
26251
  var init_currency_prices = __esm({
25605
26252
  "src/lib/currency-prices.ts"() {
25606
- __name(normalizeCurrencyCode, "normalizeCurrencyCode");
25607
- __name(parseCurrencyPrices, "parseCurrencyPrices");
25608
- __name(serializeCurrencyPrices, "serializeCurrencyPrices");
25609
- __name(currencyPricesToForm, "currencyPricesToForm");
25610
26253
  __name(parseDefaultProductPrice, "parseDefaultProductPrice");
25611
- __name(formToCurrencyPricesPayload, "formToCurrencyPricesPayload");
25612
26254
  }
25613
26255
  });
25614
26256
 
@@ -28825,428 +29467,6 @@ var init_EventProductsSection = __esm({
28825
29467
  __name(EventProductsSection, "EventProductsSection");
28826
29468
  }
28827
29469
  });
28828
- function VariableChip({ name, onCopy }) {
28829
- return /* @__PURE__ */ React.createElement("button", {
28830
- type: "button",
28831
- onClick: onCopy,
28832
- 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",
28833
- title: "Click to copy"
28834
- }, `{{${name}}}`);
28835
- }
28836
- function ChannelToggle({ label, icon: Icon2, checked, onChange }) {
28837
- return /* @__PURE__ */ React.createElement("button", {
28838
- type: "button",
28839
- role: "checkbox",
28840
- "aria-checked": checked,
28841
- onClick: onChange,
28842
- 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"}`
28843
- }, /* @__PURE__ */ React.createElement(Icon2, {
28844
- className: "h-4 w-4 shrink-0"
28845
- }), label);
28846
- }
28847
- function EventNotificationSettings({ eventId }) {
28848
- const [loading, setLoading] = useState(true);
28849
- const [saving, setSaving] = useState(false);
28850
- const [settings, setSettings] = useState(null);
28851
- const [testEmail, setTestEmail] = useState("");
28852
- const [testPhone, setTestPhone] = useState("");
28853
- const [testing, setTesting] = useState(null);
28854
- const [varsOpen, setVarsOpen] = useState(false);
28855
- const load = useCallback(async () => {
28856
- setLoading(true);
28857
- try {
28858
- const res = await fetch(`/api/events/${eventId}/notifications`);
28859
- if (!res.ok) throw new Error("Failed to load");
28860
- const data = await res.json();
28861
- setSettings(data);
28862
- } catch {
28863
- toast.error("Could not load notification settings");
28864
- } finally {
28865
- setLoading(false);
28866
- }
28867
- }, [
28868
- eventId
28869
- ]);
28870
- useEffect(() => {
28871
- void load();
28872
- }, [
28873
- load
28874
- ]);
28875
- const toggleChannel = /* @__PURE__ */ __name((ch) => {
28876
- if (!settings) return;
28877
- const has = settings.channels.includes(ch);
28878
- setSettings({
28879
- ...settings,
28880
- channels: has ? settings.channels.filter((c) => c !== ch) : [
28881
- ...settings.channels,
28882
- ch
28883
- ]
28884
- });
28885
- }, "toggleChannel");
28886
- const updateTemplate = /* @__PURE__ */ __name((ch, patch) => {
28887
- if (!settings) return;
28888
- setSettings({
28889
- ...settings,
28890
- templates: {
28891
- ...settings.templates,
28892
- [ch]: {
28893
- ...settings.templates[ch],
28894
- ...patch
28895
- }
28896
- }
28897
- });
28898
- }, "updateTemplate");
28899
- const resetTemplate = /* @__PURE__ */ __name((ch) => {
28900
- if (!settings) return;
28901
- const def = settings.globalDefaults.find((d) => d.channel === ch);
28902
- if (!def) return;
28903
- setSettings({
28904
- ...settings,
28905
- templates: {
28906
- ...settings.templates,
28907
- [ch]: {
28908
- subject: def.subject ?? "",
28909
- body: def.body,
28910
- externalTemplateRef: def.externalTemplateRef ?? ""
28911
- }
28912
- }
28913
- });
28914
- toast.success(`${ch === "email" ? "Email" : "WhatsApp"} template reset to default`);
28915
- }, "resetTemplate");
28916
- const copyVariable = /* @__PURE__ */ __name(async (name) => {
28917
- try {
28918
- await navigator.clipboard.writeText(`{{${name}}}`);
28919
- toast.success(`Copied {{${name}}}`);
28920
- } catch {
28921
- toast.error("Could not copy");
28922
- }
28923
- }, "copyVariable");
28924
- const handleSave = /* @__PURE__ */ __name(async () => {
28925
- if (!settings) return;
28926
- setSaving(true);
28927
- try {
28928
- const res = await fetch(`/api/events/${eventId}/notifications`, {
28929
- method: "PUT",
28930
- headers: {
28931
- "Content-Type": "application/json"
28932
- },
28933
- body: JSON.stringify({
28934
- enabled: settings.enabled,
28935
- channels: settings.channels,
28936
- templates: settings.templates
28937
- })
28938
- });
28939
- if (!res.ok) throw new Error();
28940
- toast.success("Notification settings saved");
28941
- await load();
28942
- } catch {
28943
- toast.error("Failed to save notification settings");
28944
- } finally {
28945
- setSaving(false);
28946
- }
28947
- }, "handleSave");
28948
- const sendTest = /* @__PURE__ */ __name(async (channel) => {
28949
- setTesting(channel);
28950
- try {
28951
- const res = await fetch(`/api/events/${eventId}/notifications/test`, {
28952
- method: "POST",
28953
- headers: {
28954
- "Content-Type": "application/json"
28955
- },
28956
- body: JSON.stringify({
28957
- channel,
28958
- email: testEmail.trim() || void 0,
28959
- phone: testPhone.trim() || void 0
28960
- })
28961
- });
28962
- const data = await res.json().catch(() => ({}));
28963
- if (!res.ok) {
28964
- toast.error(data.error ?? "Test failed");
28965
- return;
28966
- }
28967
- toast.success(data.message ?? "Test notification queued");
28968
- } catch {
28969
- toast.error("Test failed");
28970
- } finally {
28971
- setTesting(null);
28972
- }
28973
- }, "sendTest");
28974
- if (loading) {
28975
- return /* @__PURE__ */ React.createElement("div", {
28976
- className: `${panelCls} flex items-center gap-2 text-sm text-gray-500`
28977
- }, /* @__PURE__ */ React.createElement(Loader2, {
28978
- className: "h-4 w-4 animate-spin"
28979
- }), "Loading notification settings\u2026");
28980
- }
28981
- if (!settings) return null;
28982
- const emailTpl = settings.templates.email ?? {};
28983
- const waTpl = settings.templates.whatsapp ?? {};
28984
- const emailDefault = settings.globalDefaults.find((d) => d.channel === "email");
28985
- const waDefault = settings.globalDefaults.find((d) => d.channel === "whatsapp");
28986
- return /* @__PURE__ */ React.createElement("div", {
28987
- className: "space-y-5"
28988
- }, /* @__PURE__ */ React.createElement("div", {
28989
- className: panelCls
28990
- }, /* @__PURE__ */ React.createElement("div", {
28991
- className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"
28992
- }, /* @__PURE__ */ React.createElement("div", {
28993
- className: "space-y-1 min-w-0"
28994
- }, /* @__PURE__ */ React.createElement("label", {
28995
- className: "flex items-start gap-3 cursor-pointer group"
28996
- }, /* @__PURE__ */ React.createElement("input", {
28997
- type: "checkbox",
28998
- checked: settings.enabled,
28999
- onChange: /* @__PURE__ */ __name((e) => setSettings({
29000
- ...settings,
29001
- enabled: e.target.checked
29002
- }), "onChange"),
29003
- className: "mt-0.5 h-4 w-4 rounded border-gray-300"
29004
- }), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("span", {
29005
- className: "block text-sm font-medium text-gray-900 dark:text-gray-100"
29006
- }, "Send notifications when an order is placed"), /* @__PURE__ */ React.createElement("span", {
29007
- className: hintCls
29008
- }, "Uses global templates from Plugins \u2192 Event notifications. Requires Email and/or WhatsApp plugins for delivery."))))), settings.enabled ? /* @__PURE__ */ React.createElement("div", {
29009
- className: "mt-5 pt-5 border-t border-gray-100 dark:border-gray-700"
29010
- }, /* @__PURE__ */ React.createElement("p", {
29011
- className: labelCls5
29012
- }, "Channels"), /* @__PURE__ */ React.createElement("div", {
29013
- className: "flex flex-wrap gap-2"
29014
- }, /* @__PURE__ */ React.createElement(ChannelToggle, {
29015
- label: "Email",
29016
- icon: Mail,
29017
- checked: settings.channels.includes("email"),
29018
- onChange: /* @__PURE__ */ __name(() => toggleChannel("email"), "onChange")
29019
- }), /* @__PURE__ */ React.createElement(ChannelToggle, {
29020
- label: "WhatsApp",
29021
- icon: MessageCircle,
29022
- checked: settings.channels.includes("whatsapp"),
29023
- onChange: /* @__PURE__ */ __name(() => toggleChannel("whatsapp"), "onChange")
29024
- })), settings.channels.length === 0 ? /* @__PURE__ */ React.createElement("p", {
29025
- className: "mt-2 text-xs text-amber-700 dark:text-amber-400"
29026
- }, "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", {
29027
- className: panelCls
29028
- }, /* @__PURE__ */ React.createElement("button", {
29029
- type: "button",
29030
- onClick: /* @__PURE__ */ __name(() => setVarsOpen((o) => !o), "onClick"),
29031
- className: "flex w-full items-center justify-between gap-2 text-left"
29032
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
29033
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29034
- }, "Template variables"), /* @__PURE__ */ React.createElement("p", {
29035
- className: hintCls
29036
- }, "Click a variable to copy it into your template.")), varsOpen ? /* @__PURE__ */ React.createElement(ChevronUp, {
29037
- className: "h-4 w-4 shrink-0 text-gray-400"
29038
- }) : /* @__PURE__ */ React.createElement(ChevronDown, {
29039
- className: "h-4 w-4 shrink-0 text-gray-400"
29040
- })), varsOpen ? /* @__PURE__ */ React.createElement("div", {
29041
- className: "mt-3 flex flex-wrap gap-1.5"
29042
- }, settings.templateVariables.map((v) => /* @__PURE__ */ React.createElement(VariableChip, {
29043
- key: v,
29044
- name: v,
29045
- onCopy: /* @__PURE__ */ __name(() => copyVariable(v), "onCopy")
29046
- }))) : null), settings.channels.includes("email") ? /* @__PURE__ */ React.createElement("div", {
29047
- className: panelCls
29048
- }, /* @__PURE__ */ React.createElement("div", {
29049
- className: "flex flex-wrap items-center justify-between gap-3 mb-4"
29050
- }, /* @__PURE__ */ React.createElement("div", {
29051
- className: "flex items-center gap-2"
29052
- }, /* @__PURE__ */ React.createElement(Mail, {
29053
- className: "h-4 w-4 text-gray-500"
29054
- }), /* @__PURE__ */ React.createElement("h3", {
29055
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
29056
- }, "Email template")), /* @__PURE__ */ React.createElement(Button, {
29057
- type: "button",
29058
- variant: "outline",
29059
- size: "sm",
29060
- onClick: /* @__PURE__ */ __name(() => resetTemplate("email"), "onClick"),
29061
- className: "gap-1.5 h-8"
29062
- }, /* @__PURE__ */ React.createElement(RotateCcw, {
29063
- className: "h-3.5 w-3.5"
29064
- }), "Reset to default")), /* @__PURE__ */ React.createElement("div", {
29065
- className: subPanelCls
29066
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29067
- className: labelCls5
29068
- }, "Subject"), /* @__PURE__ */ React.createElement(Input, {
29069
- value: emailTpl.subject ?? "",
29070
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("email", {
29071
- subject: e.target.value
29072
- }), "onChange"),
29073
- className: "h-9 text-sm",
29074
- placeholder: emailDefault?.subject ?? "Order confirmation for {{eventName}}"
29075
- })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29076
- className: labelCls5
29077
- }, "Body"), /* @__PURE__ */ React.createElement("p", {
29078
- className: `${hintCls} mb-2`
29079
- }, "HTML is supported. Use variables from the list above."), /* @__PURE__ */ React.createElement(Textarea, {
29080
- value: emailTpl.body ?? "",
29081
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("email", {
29082
- body: e.target.value
29083
- }), "onChange"),
29084
- rows: 8,
29085
- className: "text-sm font-mono min-h-[180px] resize-y",
29086
- placeholder: emailDefault?.body ?? ""
29087
- })))) : null, settings.channels.includes("whatsapp") ? /* @__PURE__ */ React.createElement("div", {
29088
- className: panelCls
29089
- }, /* @__PURE__ */ React.createElement("div", {
29090
- className: "flex flex-wrap items-center justify-between gap-3 mb-4"
29091
- }, /* @__PURE__ */ React.createElement("div", {
29092
- className: "flex items-center gap-2"
29093
- }, /* @__PURE__ */ React.createElement(MessageCircle, {
29094
- className: "h-4 w-4 text-gray-500"
29095
- }), /* @__PURE__ */ React.createElement("h3", {
29096
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100"
29097
- }, "WhatsApp template")), /* @__PURE__ */ React.createElement(Button, {
29098
- type: "button",
29099
- variant: "outline",
29100
- size: "sm",
29101
- onClick: /* @__PURE__ */ __name(() => resetTemplate("whatsapp"), "onClick"),
29102
- className: "gap-1.5 h-8"
29103
- }, /* @__PURE__ */ React.createElement(RotateCcw, {
29104
- className: "h-3.5 w-3.5"
29105
- }), "Reset to default")), /* @__PURE__ */ React.createElement("div", {
29106
- className: subPanelCls
29107
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29108
- className: labelCls5
29109
- }, "Meta approved template name"), /* @__PURE__ */ React.createElement(Input, {
29110
- value: waTpl.externalTemplateRef ?? "",
29111
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("whatsapp", {
29112
- externalTemplateRef: e.target.value
29113
- }), "onChange"),
29114
- placeholder: waDefault?.externalTemplateRef ?? "event_order_placed",
29115
- className: "h-9 text-sm"
29116
- }), /* @__PURE__ */ React.createElement("p", {
29117
- className: `${hintCls} mt-1.5`
29118
- }, "Must match a template approved in your Meta Business account.")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
29119
- className: labelCls5
29120
- }, "Body (reference)"), /* @__PURE__ */ React.createElement("p", {
29121
- className: `${hintCls} mb-2`
29122
- }, "Used as fallback documentation; WhatsApp sends via the Meta template above."), /* @__PURE__ */ React.createElement(Textarea, {
29123
- value: waTpl.body ?? "",
29124
- onChange: /* @__PURE__ */ __name((e) => updateTemplate("whatsapp", {
29125
- body: e.target.value
29126
- }), "onChange"),
29127
- rows: 4,
29128
- className: "text-sm min-h-[100px] resize-y",
29129
- placeholder: waDefault?.body ?? ""
29130
- })))) : null, /* @__PURE__ */ React.createElement("div", {
29131
- className: panelCls
29132
- }, /* @__PURE__ */ React.createElement("p", {
29133
- className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mb-1"
29134
- }, "Send test"), /* @__PURE__ */ React.createElement("p", {
29135
- className: `${hintCls} mb-4`
29136
- }, "Queue a test notification with sample order data. Uses the templates above (save first if you changed them)."), /* @__PURE__ */ React.createElement("div", {
29137
- className: "grid gap-4 sm:grid-cols-2"
29138
- }, /* @__PURE__ */ React.createElement("div", {
29139
- className: subPanelCls
29140
- }, /* @__PURE__ */ React.createElement("div", {
29141
- className: "flex items-center gap-2 mb-3"
29142
- }, /* @__PURE__ */ React.createElement(Mail, {
29143
- className: "h-4 w-4 text-gray-500"
29144
- }), /* @__PURE__ */ React.createElement("span", {
29145
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29146
- }, "Test email")), /* @__PURE__ */ React.createElement(Label3, {
29147
- className: labelCls5
29148
- }, "Recipient"), /* @__PURE__ */ React.createElement(Input, {
29149
- value: testEmail,
29150
- onChange: /* @__PURE__ */ __name((e) => setTestEmail(e.target.value), "onChange"),
29151
- type: "email",
29152
- className: "h-9 text-sm mb-3",
29153
- placeholder: "you@example.com"
29154
- }), /* @__PURE__ */ React.createElement(Button, {
29155
- type: "button",
29156
- variant: "outline",
29157
- size: "sm",
29158
- disabled: testing !== null || !settings.channels.includes("email"),
29159
- onClick: /* @__PURE__ */ __name(() => sendTest("email"), "onClick"),
29160
- className: "gap-1.5 w-full sm:w-auto"
29161
- }, testing === "email" ? /* @__PURE__ */ React.createElement(Loader2, {
29162
- className: "h-3.5 w-3.5 animate-spin"
29163
- }) : /* @__PURE__ */ React.createElement(Send, {
29164
- className: "h-3.5 w-3.5"
29165
- }), "Send test email")), /* @__PURE__ */ React.createElement("div", {
29166
- className: subPanelCls
29167
- }, /* @__PURE__ */ React.createElement("div", {
29168
- className: "flex items-center gap-2 mb-3"
29169
- }, /* @__PURE__ */ React.createElement(MessageCircle, {
29170
- className: "h-4 w-4 text-gray-500"
29171
- }), /* @__PURE__ */ React.createElement("span", {
29172
- className: "text-sm font-medium text-gray-900 dark:text-gray-100"
29173
- }, "Test WhatsApp")), /* @__PURE__ */ React.createElement(Label3, {
29174
- className: labelCls5
29175
- }, "Phone number"), /* @__PURE__ */ React.createElement(Input, {
29176
- value: testPhone,
29177
- onChange: /* @__PURE__ */ __name((e) => setTestPhone(e.target.value), "onChange"),
29178
- className: "h-9 text-sm mb-3",
29179
- placeholder: "+91 98765 43210"
29180
- }), /* @__PURE__ */ React.createElement(Button, {
29181
- type: "button",
29182
- variant: "outline",
29183
- size: "sm",
29184
- disabled: testing !== null || !settings.channels.includes("whatsapp"),
29185
- onClick: /* @__PURE__ */ __name(() => sendTest("whatsapp"), "onClick"),
29186
- className: "gap-1.5 w-full sm:w-auto"
29187
- }, testing === "whatsapp" ? /* @__PURE__ */ React.createElement(Loader2, {
29188
- className: "h-3.5 w-3.5 animate-spin"
29189
- }) : /* @__PURE__ */ React.createElement(Send, {
29190
- className: "h-3.5 w-3.5"
29191
- }), "Send test WhatsApp"))))) : null, /* @__PURE__ */ React.createElement("div", {
29192
- className: "flex justify-end pt-1"
29193
- }, /* @__PURE__ */ React.createElement(Button, {
29194
- type: "button",
29195
- onClick: handleSave,
29196
- disabled: saving,
29197
- className: "min-w-[160px]"
29198
- }, saving ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Loader2, {
29199
- className: "h-4 w-4 animate-spin mr-2"
29200
- }), "Saving\u2026") : "Save settings")));
29201
- }
29202
- function EventNotificationSummary({ eventId }) {
29203
- const [summary, setSummary] = useState(null);
29204
- useEffect(() => {
29205
- let cancelled = false;
29206
- fetch(`/api/events/${eventId}/notifications`).then((r) => r.ok ? r.json() : null).then((data) => {
29207
- if (!cancelled && data) {
29208
- setSummary({
29209
- enabled: Boolean(data.enabled),
29210
- channels: data.channels ?? []
29211
- });
29212
- }
29213
- }).catch(() => void 0);
29214
- return () => {
29215
- cancelled = true;
29216
- };
29217
- }, [
29218
- eventId
29219
- ]);
29220
- if (!summary?.enabled) {
29221
- return /* @__PURE__ */ React.createElement("p", {
29222
- className: "text-sm text-gray-500"
29223
- }, "Order notifications: disabled");
29224
- }
29225
- const ch = summary.channels.length ? summary.channels.join(", ") : "none";
29226
- return /* @__PURE__ */ React.createElement("p", {
29227
- className: "text-sm text-gray-700 dark:text-gray-300"
29228
- }, "Order notifications: ", /* @__PURE__ */ React.createElement("span", {
29229
- className: "font-medium text-green-700 dark:text-green-400"
29230
- }, "enabled"), " (", ch, ")");
29231
- }
29232
- var panelCls, subPanelCls, labelCls5, hintCls;
29233
- var init_EventNotificationSettings = __esm({
29234
- "src/admin/components/EventNotificationSettings.tsx"() {
29235
- "use client";
29236
- init_button();
29237
- init_input();
29238
- init_label();
29239
- init_textarea();
29240
- panelCls = "rounded-lg border border-gray-200 bg-white p-4 sm:p-5 dark:border-gray-600 dark:bg-gray-900/30";
29241
- 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";
29242
- labelCls5 = "block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1.5";
29243
- hintCls = "text-xs text-gray-500 dark:text-gray-400 leading-relaxed";
29244
- __name(VariableChip, "VariableChip");
29245
- __name(ChannelToggle, "ChannelToggle");
29246
- __name(EventNotificationSettings, "EventNotificationSettings");
29247
- __name(EventNotificationSummary, "EventNotificationSummary");
29248
- }
29249
- });
29250
29470
 
29251
29471
  // src/lib/social-media-links.ts
29252
29472
  function isValidHttpUrl(value) {
@@ -29347,7 +29567,7 @@ function SocialMediaLinksForm({ fields, values, onChange }) {
29347
29567
  return /* @__PURE__ */ React.createElement("div", {
29348
29568
  key: field.key
29349
29569
  }, /* @__PURE__ */ React.createElement("label", {
29350
- className: labelCls6
29570
+ className: labelCls5
29351
29571
  }, field.label), /* @__PURE__ */ React.createElement("div", {
29352
29572
  className: "relative"
29353
29573
  }, Icon2 ? /* @__PURE__ */ React.createElement(Icon2, {
@@ -29468,52 +29688,14 @@ function SupportedCurrenciesPicker({ currencies, defaultCurrency, supported, onD
29468
29688
  className: "mt-1 text-xs text-gray-500"
29469
29689
  }, "Default currency is always included.")));
29470
29690
  }
29471
- 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" }) {
29472
- const base = defaultCurrency.trim().toUpperCase() || "INR";
29473
- const others = currencies.filter((c) => c.code.toUpperCase() !== base);
29474
- return /* @__PURE__ */ React.createElement("div", {
29475
- className: "space-y-4"
29476
- }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
29477
- className: labelClassName
29478
- }, base, " price ", /* @__PURE__ */ React.createElement("span", {
29479
- className: "text-red-600"
29480
- }, "*")), /* @__PURE__ */ React.createElement("input", {
29481
- type: "number",
29482
- min: 0,
29483
- step: "any",
29484
- value: defaultPrice,
29485
- onChange: /* @__PURE__ */ __name((e) => onDefaultPriceChange(e.target.value), "onChange"),
29486
- className: inputClassName,
29487
- required: true
29488
- })), others.length > 0 ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
29489
- className: `${labelClassName} mb-2`
29490
- }, "Additional currencies (optional)"), /* @__PURE__ */ React.createElement("div", {
29491
- className: "grid gap-3 sm:grid-cols-2"
29492
- }, others.map((c) => {
29493
- const code = c.code.toUpperCase();
29494
- return /* @__PURE__ */ React.createElement("div", {
29495
- key: code
29496
- }, /* @__PURE__ */ React.createElement("label", {
29497
- className: labelClassName
29498
- }, code), /* @__PURE__ */ React.createElement("input", {
29499
- type: "number",
29500
- min: 0,
29501
- step: "any",
29502
- value: additionalPrices[code] ?? "",
29503
- onChange: /* @__PURE__ */ __name((e) => onAdditionalPriceChange(code, e.target.value), "onChange"),
29504
- className: inputClassName,
29505
- placeholder: "Optional"
29506
- }));
29507
- }))) : null);
29508
- }
29509
- var inputCls5, labelCls6, ICONS;
29691
+ var inputCls5, labelCls5, ICONS;
29510
29692
  var init_EventManagementFields = __esm({
29511
29693
  "src/components/Admin/EventManagementFields.tsx"() {
29512
29694
  "use client";
29513
29695
  init_social_brand_icons();
29514
29696
  init_social_media_links();
29515
29697
  inputCls5 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm pl-9";
29516
- labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
29698
+ labelCls5 = "block text-xs font-medium text-gray-600 mb-1";
29517
29699
  ICONS = {
29518
29700
  facebook: FacebookBrandIcon,
29519
29701
  instagram: InstagramBrandIcon,
@@ -29527,7 +29709,6 @@ var init_EventManagementFields = __esm({
29527
29709
  __name(SocialMediaLinksDisplay, "SocialMediaLinksDisplay");
29528
29710
  __name(TimezoneSelect, "TimezoneSelect");
29529
29711
  __name(SupportedCurrenciesPicker, "SupportedCurrenciesPicker");
29530
- __name(MultiCurrencyPriceFields, "MultiCurrencyPriceFields");
29531
29712
  }
29532
29713
  });
29533
29714
 
@@ -29679,28 +29860,11 @@ function intersectSupportedCurrencies(supported, defaultCurrency, options) {
29679
29860
  ])
29680
29861
  ];
29681
29862
  }
29682
- function currencyOptionsIncluding(options, codes) {
29683
- const map = new Map(options.map((o) => [
29684
- o.code.toUpperCase(),
29685
- o
29686
- ]));
29687
- for (const code of codes) {
29688
- const normalized = code.trim().toUpperCase();
29689
- if (!normalized || map.has(normalized)) continue;
29690
- map.set(normalized, {
29691
- code: normalized
29692
- });
29693
- }
29694
- return [
29695
- ...map.values()
29696
- ].sort((a, b) => a.code.localeCompare(b.code));
29697
- }
29698
29863
  var init_currency_options = __esm({
29699
29864
  "src/lib/currency-options.ts"() {
29700
29865
  __name(parseCurrencyApiRows, "parseCurrencyApiRows");
29701
29866
  __name(fetchActiveCurrencyOptions, "fetchActiveCurrencyOptions");
29702
29867
  __name(intersectSupportedCurrencies, "intersectSupportedCurrencies");
29703
- __name(currencyOptionsIncluding, "currencyOptionsIncluding");
29704
29868
  }
29705
29869
  });
29706
29870
 
@@ -29889,7 +30053,7 @@ __export(EventEditPage_exports, {
29889
30053
  });
29890
30054
  function RequiredLabel({ children }) {
29891
30055
  return /* @__PURE__ */ React.createElement("label", {
29892
- className: labelCls7
30056
+ className: labelCls6
29893
30057
  }, children, " ", /* @__PURE__ */ React.createElement("span", {
29894
30058
  className: "text-red-600"
29895
30059
  }, "*"));
@@ -30334,21 +30498,21 @@ function EventEditPage({ eventId }) {
30334
30498
  }, /* @__PURE__ */ React.createElement("div", {
30335
30499
  className: "sm:col-span-2"
30336
30500
  }, /* @__PURE__ */ React.createElement("label", {
30337
- className: labelCls7
30501
+ className: labelCls6
30338
30502
  }, "Name"), /* @__PURE__ */ React.createElement("input", {
30339
30503
  type: "text",
30340
30504
  value: name,
30341
30505
  onChange: /* @__PURE__ */ __name((e) => setName(e.target.value), "onChange"),
30342
30506
  className: inputCls6
30343
30507
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30344
- className: labelCls7
30508
+ className: labelCls6
30345
30509
  }, "Slug"), /* @__PURE__ */ React.createElement("input", {
30346
30510
  type: "text",
30347
30511
  value: slug,
30348
30512
  onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
30349
30513
  className: inputCls6
30350
30514
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30351
- className: labelCls7
30515
+ className: labelCls6
30352
30516
  }, "Sort order"), /* @__PURE__ */ React.createElement("input", {
30353
30517
  type: "number",
30354
30518
  value: sortOrder,
@@ -30357,7 +30521,7 @@ function EventEditPage({ eventId }) {
30357
30521
  })), /* @__PURE__ */ React.createElement("div", {
30358
30522
  className: "sm:col-span-2"
30359
30523
  }, /* @__PURE__ */ React.createElement("label", {
30360
- className: labelCls7
30524
+ className: labelCls6
30361
30525
  }, "Description"), /* @__PURE__ */ React.createElement("div", {
30362
30526
  className: "rounded-md border border-gray-300 bg-white overflow-hidden"
30363
30527
  }, /* @__PURE__ */ React.createElement(JoditRichText, {
@@ -30368,7 +30532,7 @@ function EventEditPage({ eventId }) {
30368
30532
  }))), /* @__PURE__ */ React.createElement("div", {
30369
30533
  className: "sm:col-span-2"
30370
30534
  }, /* @__PURE__ */ React.createElement("label", {
30371
- className: labelCls7
30535
+ className: labelCls6
30372
30536
  }, "Entity types"), /* @__PURE__ */ React.createElement("div", {
30373
30537
  className: "flex flex-wrap gap-2"
30374
30538
  }, ENTITY_TYPE_OPTIONS.map((type) => /* @__PURE__ */ React.createElement("label", {
@@ -30384,7 +30548,7 @@ function EventEditPage({ eventId }) {
30384
30548
  }, type)))), /* @__PURE__ */ React.createElement("div", {
30385
30549
  className: "mt-3 space-y-2"
30386
30550
  }, /* @__PURE__ */ React.createElement("label", {
30387
- className: labelCls7
30551
+ className: labelCls6
30388
30552
  }, "Custom entity type"), /* @__PURE__ */ React.createElement("div", {
30389
30553
  className: "flex flex-wrap gap-2"
30390
30554
  }, /* @__PURE__ */ React.createElement("input", {
@@ -30424,7 +30588,7 @@ function EventEditPage({ eventId }) {
30424
30588
  onChange: setBannerImageUrl,
30425
30589
  previewVariant: "banner",
30426
30590
  inputClassName: inputCls6,
30427
- labelClassName: labelCls7
30591
+ labelClassName: labelCls6
30428
30592
  })), /* @__PURE__ */ React.createElement("div", {
30429
30593
  className: "sm:col-span-2"
30430
30594
  }, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
@@ -30433,9 +30597,9 @@ function EventEditPage({ eventId }) {
30433
30597
  onChange: setLogoUrl,
30434
30598
  previewVariant: "logo",
30435
30599
  inputClassName: inputCls6,
30436
- labelClassName: labelCls7
30600
+ labelClassName: labelCls6
30437
30601
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30438
- className: labelCls7
30602
+ className: labelCls6
30439
30603
  }, "Pricing type"), /* @__PURE__ */ React.createElement("select", {
30440
30604
  value: pricingType,
30441
30605
  onChange: /* @__PURE__ */ __name((e) => setPricingType(e.target.value), "onChange"),
@@ -30447,7 +30611,7 @@ function EventEditPage({ eventId }) {
30447
30611
  }, "Free"), /* @__PURE__ */ React.createElement("option", {
30448
30612
  value: "paid"
30449
30613
  }, "Paid"))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30450
- className: labelCls7
30614
+ className: labelCls6
30451
30615
  }, "Mode"), /* @__PURE__ */ React.createElement("select", {
30452
30616
  value: entityMode,
30453
30617
  onChange: /* @__PURE__ */ __name((e) => setEntityMode(e.target.value), "onChange"),
@@ -30467,7 +30631,7 @@ function EventEditPage({ eventId }) {
30467
30631
  }, /* @__PURE__ */ React.createElement("div", {
30468
30632
  className: "sm:col-span-2"
30469
30633
  }, /* @__PURE__ */ React.createElement("label", {
30470
- className: labelCls7
30634
+ className: labelCls6
30471
30635
  }, "Venue"), /* @__PURE__ */ React.createElement("input", {
30472
30636
  type: "text",
30473
30637
  value: venue,
@@ -30476,7 +30640,7 @@ function EventEditPage({ eventId }) {
30476
30640
  })), /* @__PURE__ */ React.createElement("div", {
30477
30641
  className: "sm:col-span-2"
30478
30642
  }, /* @__PURE__ */ React.createElement("label", {
30479
- className: labelCls7
30643
+ className: labelCls6
30480
30644
  }, "Additional venue details"), /* @__PURE__ */ React.createElement("textarea", {
30481
30645
  value: additionalVenueDetails,
30482
30646
  onChange: /* @__PURE__ */ __name((e) => setAdditionalVenueDetails(e.target.value.slice(0, ADDITIONAL_VENUE_MAX_CHARS)), "onChange"),
@@ -30487,14 +30651,14 @@ function EventEditPage({ eventId }) {
30487
30651
  }), /* @__PURE__ */ React.createElement("p", {
30488
30652
  className: "mt-1 text-xs text-gray-500 text-right"
30489
30653
  }, additionalVenueDetails.length, " / ", ADDITIONAL_VENUE_MAX_CHARS, " characters")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30490
- className: labelCls7
30654
+ className: labelCls6
30491
30655
  }, "City"), /* @__PURE__ */ React.createElement("input", {
30492
30656
  type: "text",
30493
30657
  value: city,
30494
30658
  onChange: /* @__PURE__ */ __name((e) => setCity(e.target.value), "onChange"),
30495
30659
  className: inputCls6
30496
30660
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30497
- className: labelCls7
30661
+ className: labelCls6
30498
30662
  }, "Country"), /* @__PURE__ */ React.createElement("input", {
30499
30663
  type: "text",
30500
30664
  value: country,
@@ -30525,14 +30689,14 @@ function EventEditPage({ eventId }) {
30525
30689
  className: inputCls6,
30526
30690
  required: true
30527
30691
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30528
- className: labelCls7
30692
+ className: labelCls6
30529
30693
  }, "Registration opens"), /* @__PURE__ */ React.createElement("input", {
30530
30694
  type: "datetime-local",
30531
30695
  value: registrationOpensAt,
30532
30696
  onChange: /* @__PURE__ */ __name((e) => setRegistrationOpensAt(e.target.value), "onChange"),
30533
30697
  className: inputCls6
30534
30698
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30535
- className: labelCls7
30699
+ className: labelCls6
30536
30700
  }, "Registration closes"), /* @__PURE__ */ React.createElement("input", {
30537
30701
  type: "datetime-local",
30538
30702
  value: registrationClosesAt,
@@ -30553,20 +30717,20 @@ function EventEditPage({ eventId }) {
30553
30717
  onDefaultChange: setDefaultCurrency,
30554
30718
  onSupportedChange: setSupportedCurrencies,
30555
30719
  inputCls: inputCls6,
30556
- labelCls: labelCls7
30720
+ labelCls: labelCls6
30557
30721
  }) : /* @__PURE__ */ React.createElement("p", {
30558
30722
  className: "text-sm text-gray-500"
30559
30723
  }, "No active currencies configured. Add currencies in Store settings first."), /* @__PURE__ */ React.createElement("div", {
30560
30724
  className: "grid gap-3 sm:grid-cols-2"
30561
30725
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30562
- className: labelCls7
30726
+ className: labelCls6
30563
30727
  }, "Official website URL"), /* @__PURE__ */ React.createElement("input", {
30564
30728
  type: "url",
30565
30729
  value: officialWebsiteUrl,
30566
30730
  onChange: /* @__PURE__ */ __name((e) => setOfficialWebsiteUrl(e.target.value), "onChange"),
30567
30731
  className: inputCls6
30568
30732
  })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30569
- className: labelCls7
30733
+ className: labelCls6
30570
30734
  }, "Support contact"), /* @__PURE__ */ React.createElement("input", {
30571
30735
  type: "text",
30572
30736
  value: supportContact,
@@ -30575,7 +30739,7 @@ function EventEditPage({ eventId }) {
30575
30739
  })), /* @__PURE__ */ React.createElement("div", {
30576
30740
  className: "sm:col-span-2"
30577
30741
  }, /* @__PURE__ */ React.createElement("label", {
30578
- className: labelCls7
30742
+ className: labelCls6
30579
30743
  }, "Contact form"), /* @__PURE__ */ React.createElement("select", {
30580
30744
  value: contactFormId ?? "",
30581
30745
  onChange: /* @__PURE__ */ __name((e) => setContactFormId(e.target.value ? Number(e.target.value) : null), "onChange"),
@@ -30590,7 +30754,7 @@ function EventEditPage({ eventId }) {
30590
30754
  }, "Attendee registration form used during checkout for this event.")), /* @__PURE__ */ React.createElement("div", {
30591
30755
  className: "sm:col-span-2 grid gap-4 sm:grid-cols-2 sm:items-end"
30592
30756
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
30593
- className: labelCls7
30757
+ className: labelCls6
30594
30758
  }, "Max group purchase quantity"), /* @__PURE__ */ React.createElement("input", {
30595
30759
  type: "number",
30596
30760
  value: maxGroupPurchaseQuantity,
@@ -30626,13 +30790,7 @@ function EventEditPage({ eventId }) {
30626
30790
  ...prev,
30627
30791
  [key]: value
30628
30792
  })), "onChange")
30629
- })), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
30630
- className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3"
30631
- }, "Order notifications"), eventRecordId ? /* @__PURE__ */ React.createElement(EventNotificationSettings, {
30632
- eventId: eventRecordId
30633
- }) : /* @__PURE__ */ React.createElement("p", {
30634
- className: "text-sm text-gray-500"
30635
- }, "Save the event first to configure order notification channels and templates."))))
30793
+ }))))
30636
30794
  }), showEventProducts ? /* @__PURE__ */ React.createElement("div", {
30637
30795
  className: "border-t border-gray-200 px-4 py-4 sm:px-6"
30638
30796
  }, /* @__PURE__ */ React.createElement(EventProductsSection, {
@@ -30640,7 +30798,7 @@ function EventEditPage({ eventId }) {
30640
30798
  returnUrl: eventEditUrl
30641
30799
  })) : null);
30642
30800
  }
30643
- var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls5, labelCls7, inputCls6, ENTITY_TYPE_OPTIONS;
30801
+ var ADDITIONAL_VENUE_MAX_CHARS, DEFAULT_EVENT_TIMEZONE, DEFAULT_EVENT_CURRENCY, EVENT_SOCIAL_KEYS, isCreate4, sectionCls5, labelCls6, inputCls6, ENTITY_TYPE_OPTIONS;
30644
30802
  var init_EventEditPage = __esm({
30645
30803
  "src/admin/pages/EventEditPage.tsx"() {
30646
30804
  "use client";
@@ -30650,7 +30808,6 @@ var init_EventEditPage = __esm({
30650
30808
  init_ImageOrUrlField();
30651
30809
  init_JoditRichText();
30652
30810
  init_EventProductsSection();
30653
- init_EventNotificationSettings();
30654
30811
  init_EventManagementFields();
30655
30812
  init_event_named_lists();
30656
30813
  init_social_media_links();
@@ -30663,7 +30820,7 @@ var init_EventEditPage = __esm({
30663
30820
  EVENT_SOCIAL_KEYS = EVENT_SOCIAL_FIELDS.map((f) => f.key);
30664
30821
  isCreate4 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
30665
30822
  sectionCls5 = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50";
30666
- labelCls7 = "block text-xs font-medium text-gray-600 mb-1";
30823
+ labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
30667
30824
  inputCls6 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
30668
30825
  __name(RequiredLabel, "RequiredLabel");
30669
30826
  ENTITY_TYPE_OPTIONS = [
@@ -30687,25 +30844,14 @@ function formatDateTimeLocal(value) {
30687
30844
  if (isNaN(date.getTime())) return "";
30688
30845
  return date.toISOString().slice(0, 16);
30689
30846
  }
30690
- async function fetchEventPricing(eventId) {
30847
+ async function fetchEventDefaultCurrency(eventId) {
30691
30848
  try {
30692
30849
  const res = await fetch(`/api/events/${eventId}`);
30693
- if (!res.ok) return DEFAULT_PRICING;
30850
+ if (!res.ok) return "INR";
30694
30851
  const data = await res.json();
30695
- const defaultCurrency = String(data.defaultCurrency ?? "INR").trim().toUpperCase() || "INR";
30696
- const supported = Array.isArray(data.supportedCurrencies) ? data.supportedCurrencies.map((c) => String(c).trim().toUpperCase()).filter((c) => Boolean(c)) : [
30697
- defaultCurrency
30698
- ];
30699
- const set = new Set(supported);
30700
- set.add(defaultCurrency);
30701
- return {
30702
- defaultCurrency,
30703
- supportedCurrencies: [
30704
- ...set
30705
- ]
30706
- };
30852
+ return String(data.defaultCurrency ?? "INR").trim().toUpperCase() || "INR";
30707
30853
  } catch {
30708
- return DEFAULT_PRICING;
30854
+ return "INR";
30709
30855
  }
30710
30856
  }
30711
30857
  async function validateComboProductInventory(productIds) {
@@ -30747,10 +30893,8 @@ function ComboEditPage({ comboId }) {
30747
30893
  const [name, setName] = useState("");
30748
30894
  const [desc, setDesc] = useState("");
30749
30895
  const [eventId, setEventId] = useState("");
30750
- const [defaultPriceStr, setDefaultPriceStr] = useState("");
30751
- const [additionalPrices, setAdditionalPrices] = useState({});
30752
- const [pricingConfig, setPricingConfig] = useState(DEFAULT_PRICING);
30753
- const [currencySchemaOptions, setCurrencySchemaOptions] = useState([]);
30896
+ const [priceStr, setPriceStr] = useState("");
30897
+ const [defaultCurrency, setDefaultCurrency] = useState("INR");
30754
30898
  const [minSelectableItems, setMinSelectableItems] = useState(1);
30755
30899
  const [maxSelectableItems, setMaxSelectableItems] = useState(1);
30756
30900
  const [status, setStatus] = useState("active");
@@ -30760,23 +30904,14 @@ function ComboEditPage({ comboId }) {
30760
30904
  const [productOptions, setProductOptions] = useState([]);
30761
30905
  const [fixedItems, setFixedItems] = useState([]);
30762
30906
  const [addonItems, setAddonItems] = useState([]);
30763
- useEffect(() => {
30764
- let cancelled = false;
30765
- fetchActiveCurrencyOptions().then(({ options }) => {
30766
- if (!cancelled && options.length) setCurrencySchemaOptions(options);
30767
- });
30768
- return () => {
30769
- cancelled = true;
30770
- };
30771
- }, []);
30772
30907
  useEffect(() => {
30773
30908
  if (!eventId) {
30774
- setPricingConfig(DEFAULT_PRICING);
30909
+ setDefaultCurrency("INR");
30775
30910
  return;
30776
30911
  }
30777
30912
  let cancelled = false;
30778
- fetchEventPricing(eventId).then((config) => {
30779
- if (!cancelled) setPricingConfig(config);
30913
+ fetchEventDefaultCurrency(eventId).then((code) => {
30914
+ if (!cancelled) setDefaultCurrency(code);
30780
30915
  });
30781
30916
  return () => {
30782
30917
  cancelled = true;
@@ -30784,10 +30919,6 @@ function ComboEditPage({ comboId }) {
30784
30919
  }, [
30785
30920
  eventId
30786
30921
  ]);
30787
- const pricingCurrencyOptions = currencyOptionsIncluding(currencySchemaOptions, [
30788
- pricingConfig.defaultCurrency,
30789
- ...pricingConfig.supportedCurrencies
30790
- ]).filter((c) => pricingConfig.supportedCurrencies.map((x) => x.toUpperCase()).includes(c.code.toUpperCase()));
30791
30922
  useEffect(() => {
30792
30923
  let cancelled = false;
30793
30924
  (async () => {
@@ -30876,11 +31007,11 @@ function ComboEditPage({ comboId }) {
30876
31007
  setName(data.name ?? "");
30877
31008
  setDesc(data.desc ?? "");
30878
31009
  setEventId(data.eventId != null ? String(data.eventId) : "");
30879
- const eventPricing = data.eventId != null ? await fetchEventPricing(String(data.eventId)) : DEFAULT_PRICING;
30880
- if (!cancelled) setPricingConfig(eventPricing);
30881
- const { defaultPrice, additional } = currencyPricesToForm(eventPricing.defaultCurrency, data.price != null ? Number(data.price) : null, data.currencyPrices);
30882
- setDefaultPriceStr(defaultPrice);
30883
- setAdditionalPrices(additional);
31010
+ if (data.eventId != null) {
31011
+ const currency = await fetchEventDefaultCurrency(String(data.eventId));
31012
+ if (!cancelled) setDefaultCurrency(currency);
31013
+ }
31014
+ setPriceStr(data.price != null && Number.isFinite(Number(data.price)) ? String(data.price) : "");
30884
31015
  setMinSelectableItems(Number(data.minSelectableItems) || 1);
30885
31016
  setMaxSelectableItems(Number(data.maxSelectableItems) || 1);
30886
31017
  setStatus(data.status ?? "active");
@@ -30931,10 +31062,6 @@ function ComboEditPage({ comboId }) {
30931
31062
  create,
30932
31063
  duplicateSourceId
30933
31064
  ]);
30934
- /* @__PURE__ */ new Set([
30935
- ...fixedItems.map((i) => i.productId),
30936
- ...addonItems.map((i) => i.productId)
30937
- ]);
30938
31065
  const availableForFixed = productOptions.filter((p) => !addonItems.some((i) => i.productId === p.value));
30939
31066
  const availableForAddon = productOptions.filter((p) => !fixedItems.some((i) => i.productId === p.value));
30940
31067
  const addFixed = /* @__PURE__ */ __name((val) => {
@@ -30975,16 +31102,16 @@ function ComboEditPage({ comboId }) {
30975
31102
  ]);
30976
31103
  return;
30977
31104
  }
30978
- if (!defaultPriceStr.trim()) {
31105
+ if (!priceStr.trim()) {
30979
31106
  setErrors([
30980
- `${pricingConfig.defaultCurrency} price is required`
31107
+ `Price (${defaultCurrency}) is required`
30981
31108
  ]);
30982
31109
  return;
30983
31110
  }
30984
- const pricingPayload = formToCurrencyPricesPayload(pricingConfig.defaultCurrency, defaultPriceStr, additionalPrices);
30985
- if (!pricingPayload) {
31111
+ const price = Number(priceStr);
31112
+ if (!Number.isFinite(price) || price < 0) {
30986
31113
  setErrors([
30987
- `${pricingConfig.defaultCurrency} price must be a valid number`
31114
+ `Price (${defaultCurrency}) must be a valid non-negative number`
30988
31115
  ]);
30989
31116
  return;
30990
31117
  }
@@ -31032,8 +31159,8 @@ function ComboEditPage({ comboId }) {
31032
31159
  name: trimmedName,
31033
31160
  desc: desc || null,
31034
31161
  eventId: Number(trimmedEventId),
31035
- price: pricingPayload.price,
31036
- currencyPrices: pricingPayload.currencyPrices,
31162
+ price,
31163
+ currencyPrices: null,
31037
31164
  minSelectableItems,
31038
31165
  maxSelectableItems,
31039
31166
  status,
@@ -31200,21 +31327,19 @@ function ComboEditPage({ comboId }) {
31200
31327
  className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
31201
31328
  }, "Pricing & add-on selection"), /* @__PURE__ */ React.createElement("div", {
31202
31329
  className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-4"
31203
- }, eventId ? /* @__PURE__ */ React.createElement(MultiCurrencyPriceFields, {
31204
- defaultCurrency: pricingConfig.defaultCurrency,
31205
- currencies: pricingCurrencyOptions,
31206
- defaultPrice: defaultPriceStr,
31207
- additionalPrices,
31208
- onDefaultPriceChange: setDefaultPriceStr,
31209
- onAdditionalPriceChange: /* @__PURE__ */ __name((code, value) => setAdditionalPrices((prev) => ({
31210
- ...prev,
31211
- [code]: value
31212
- })), "onAdditionalPriceChange"),
31213
- labelCls: "block text-xs font-medium text-gray-600 mb-1",
31214
- inputCls: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
31215
- }) : /* @__PURE__ */ React.createElement("p", {
31216
- className: "text-sm text-gray-500"
31217
- }, "Select an event to configure combo pricing currencies."), /* @__PURE__ */ React.createElement("div", {
31330
+ }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
31331
+ className: "block text-xs font-medium text-gray-600 mb-1"
31332
+ }, "Price (", defaultCurrency, ") *"), /* @__PURE__ */ React.createElement("input", {
31333
+ type: "number",
31334
+ min: 0,
31335
+ step: "0.01",
31336
+ value: priceStr,
31337
+ onChange: /* @__PURE__ */ __name((e) => setPriceStr(e.target.value), "onChange"),
31338
+ disabled: !eventId,
31339
+ className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm disabled:bg-gray-100"
31340
+ }), /* @__PURE__ */ React.createElement("p", {
31341
+ className: "text-xs text-gray-400 mt-1"
31342
+ }, eventId ? "Other currencies use the event\u2019s supported currencies and exchange rates." : "Select an event to set the combo price.")), /* @__PURE__ */ React.createElement("div", {
31218
31343
  className: "grid grid-cols-2 gap-4"
31219
31344
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
31220
31345
  className: "block text-xs font-medium text-gray-600 mb-1"
@@ -31272,26 +31397,17 @@ function ComboEditPage({ comboId }) {
31272
31397
  sidebar: /* @__PURE__ */ React.createElement(React.Fragment, null)
31273
31398
  }));
31274
31399
  }
31275
- var isCreate5, DEFAULT_PRICING;
31400
+ var isCreate5;
31276
31401
  var init_ComboEditPage = __esm({
31277
31402
  "src/admin/pages/ComboEditPage.tsx"() {
31278
31403
  "use client";
31279
31404
  init_admin_list_return_url();
31280
31405
  init_DetailPageLayout();
31281
31406
  init_DetailPageHeader();
31282
- init_EventManagementFields();
31283
- init_currency_options();
31284
- init_currency_prices();
31285
31407
  init_inventory_validation();
31286
31408
  isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
31287
31409
  __name(formatDateTimeLocal, "formatDateTimeLocal");
31288
- DEFAULT_PRICING = {
31289
- defaultCurrency: "INR",
31290
- supportedCurrencies: [
31291
- "INR"
31292
- ]
31293
- };
31294
- __name(fetchEventPricing, "fetchEventPricing");
31410
+ __name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
31295
31411
  __name(validateComboProductInventory, "validateComboProductInventory");
31296
31412
  __name(ComboEditPage, "ComboEditPage");
31297
31413
  }
@@ -32058,35 +32174,48 @@ var VendorCategoryWorkspacePage_exports = {};
32058
32174
  __export(VendorCategoryWorkspacePage_exports, {
32059
32175
  default: () => VendorCategoryWorkspacePage
32060
32176
  });
32061
- function buildAdminProductColumns(base) {
32177
+ function buildAdminProductColumns(base, multiVendorEnabled, eventsEnabled) {
32178
+ const extraColumns = [
32179
+ ...multiVendorEnabled ? [
32180
+ VENDOR_EXTRA_COLUMN
32181
+ ] : [],
32182
+ ...eventsEnabled ? [
32183
+ EVENT_EXTRA_COLUMN
32184
+ ] : []
32185
+ ];
32062
32186
  const cols = base.filter((c) => c.field && !CATEGORY_PRODUCT_HIDDEN_FIELDS.has(c.field));
32063
32187
  const nameIdx = cols.findIndex((c) => c.field === "name");
32064
32188
  if (nameIdx < 0) return [
32065
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32189
+ ...extraColumns,
32066
32190
  ...cols
32067
32191
  ];
32068
32192
  return [
32069
32193
  ...cols.slice(0, nameIdx + 1),
32070
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32194
+ ...extraColumns,
32071
32195
  ...cols.slice(nameIdx + 1)
32072
32196
  ];
32073
32197
  }
32074
- function buildAdminAllProductColumns(base) {
32198
+ function buildAllProductColumns(base, multiVendorEnabled, eventsEnabled) {
32199
+ const extraColumns = [
32200
+ ...multiVendorEnabled ? [
32201
+ VENDOR_EXTRA_COLUMN
32202
+ ] : [],
32203
+ ...eventsEnabled ? [
32204
+ EVENT_EXTRA_COLUMN
32205
+ ] : []
32206
+ ];
32075
32207
  const cols = base.filter((c) => Boolean(c.field));
32076
32208
  const nameIdx = cols.findIndex((c) => c.field === "name");
32077
32209
  if (nameIdx < 0) return [
32078
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32210
+ ...extraColumns,
32079
32211
  ...cols
32080
32212
  ];
32081
32213
  return [
32082
32214
  ...cols.slice(0, nameIdx + 1),
32083
- ...CATEGORY_PRODUCT_EXTRA_COLUMNS,
32215
+ ...extraColumns,
32084
32216
  ...cols.slice(nameIdx + 1)
32085
32217
  ];
32086
32218
  }
32087
- function buildVendorProductColumns(base) {
32088
- return base.filter((c) => c.field !== "categoryId" && c.field !== "vendorId");
32089
- }
32090
32219
  function withCollectionRelationApi(columns, categoryId, vendorPortal) {
32091
32220
  const relationApi = collectionsRelationApi({
32092
32221
  vendorPortal,
@@ -32098,47 +32227,34 @@ function withCollectionRelationApi(columns, categoryId, vendorPortal) {
32098
32227
  } : col);
32099
32228
  }
32100
32229
  function VendorCategoryWorkspacePage() {
32101
- const router = useRouter();
32102
32230
  const searchParams = useSearchParams();
32103
32231
  const { data: session } = useSession();
32104
32232
  const vendorPortal = isVendorPortalUser(session?.user);
32233
+ const { multiVendorEnabled, eventsEnabled } = useContext(AdminConfigContext);
32105
32234
  const { categories, loading, error } = useCatalogCategories();
32106
32235
  const categoryIdParam = searchParams.get("categoryId")?.trim() ?? "";
32107
32236
  const activeCategoryId = useMemo(() => {
32108
32237
  if (categoryIdParam && categories.some((c) => String(c.id) === categoryIdParam)) {
32109
32238
  return categoryIdParam;
32110
32239
  }
32111
- if (vendorPortal) {
32112
- const first = categories[0];
32113
- return first ? String(first.id) : "";
32114
- }
32115
32240
  return "";
32116
32241
  }, [
32117
32242
  categoryIdParam,
32118
- categories,
32119
- vendorPortal
32120
- ]);
32121
- useEffect(() => {
32122
- if (!vendorPortal) return;
32123
- if (!activeCategoryId || activeCategoryId === categoryIdParam) return;
32124
- router.replace(vendorCategoryWorkspaceUrl(activeCategoryId));
32125
- }, [
32126
- activeCategoryId,
32127
- categoryIdParam,
32128
- router,
32129
- vendorPortal
32243
+ categories
32130
32244
  ]);
32131
32245
  const activeCategory = categories.find((c) => String(c.id) === activeCategoryId);
32132
- const showAllProducts = !vendorPortal && !activeCategoryId;
32133
- const workspaceFrom = activeCategoryId ? vendorCategoryWorkspaceUrl(activeCategoryId) : "/admin/products";
32246
+ const showAllProducts = !activeCategoryId;
32247
+ const workspaceFrom = activeCategoryId ? `/admin/products?categoryId=${activeCategoryId}` : "/admin/products";
32134
32248
  const itemLabel = activeCategory ? categorySingularName(activeCategory.name) : "Product";
32135
32249
  const productColumns2 = useMemo(() => {
32136
- const base = vendorPortal ? buildVendorProductColumns(STORE_CRUD_CONFIGS.products.columns) : showAllProducts ? buildAdminAllProductColumns(STORE_CRUD_CONFIGS.products.columns) : buildAdminProductColumns(STORE_CRUD_CONFIGS.products.columns);
32250
+ const base = showAllProducts ? buildAllProductColumns(STORE_CRUD_CONFIGS.products.columns, multiVendorEnabled !== false, eventsEnabled !== false) : buildAdminProductColumns(STORE_CRUD_CONFIGS.products.columns, multiVendorEnabled !== false, eventsEnabled !== false);
32137
32251
  return withCollectionRelationApi(base, activeCategoryId, vendorPortal);
32138
32252
  }, [
32139
32253
  vendorPortal,
32140
32254
  activeCategoryId,
32141
- showAllProducts
32255
+ showAllProducts,
32256
+ multiVendorEnabled,
32257
+ eventsEnabled
32142
32258
  ]);
32143
32259
  const productFilterColumns2 = useMemo(() => productColumns2, [
32144
32260
  productColumns2
@@ -32155,20 +32271,8 @@ function VendorCategoryWorkspacePage() {
32155
32271
  className: "text-red-600 text-sm"
32156
32272
  }, error));
32157
32273
  }
32158
- if (categories.length === 0) {
32159
- return /* @__PURE__ */ React26__default.createElement("div", {
32160
- className: "rounded-lg bg-white p-6 shadow-md"
32161
- }, /* @__PURE__ */ React26__default.createElement("h1", {
32162
- className: "text-lg font-semibold text-gray-900"
32163
- }, "Store"), /* @__PURE__ */ React26__default.createElement("p", {
32164
- className: "mt-2 text-sm text-gray-600"
32165
- }, "No catalog categories are available yet. Ask your platform administrator to add store categories."));
32166
- }
32167
- if (!showAllProducts && (!activeCategoryId || !activeCategory)) {
32168
- return null;
32169
- }
32170
- const listTitle = showAllProducts ? "Products" : activeCategory.name;
32171
- const listKey = showAllProducts ? "products-all-admin" : `products-${activeCategoryId}-${vendorPortal ? "vendor" : "admin"}`;
32274
+ const listTitle = showAllProducts ? "Products" : activeCategory?.name ?? "Products";
32275
+ const listKey = showAllProducts ? "products-all" : `products-${activeCategoryId}`;
32172
32276
  return /* @__PURE__ */ React26__default.createElement("div", {
32173
32277
  className: "rounded-lg bg-white shadow-md min-h-[420px]"
32174
32278
  }, /* @__PURE__ */ React26__default.createElement("div", {
@@ -32192,12 +32296,10 @@ function VendorCategoryWorkspacePage() {
32192
32296
  ...activeCategoryId ? {
32193
32297
  categoryId: activeCategoryId
32194
32298
  } : {},
32195
- ...!vendorPortal ? {
32196
- includeEventNames: "1"
32197
- } : {}
32299
+ includeEventNames: "1"
32198
32300
  },
32199
32301
  emptyState: {
32200
- title: showAllProducts ? "No products found" : `No ${activeCategory.name.toLowerCase()} found`,
32302
+ title: showAllProducts ? "No products found" : `No ${(activeCategory?.name ?? "product").toLowerCase()} found`,
32201
32303
  description: showAllProducts ? "Add a product to get started." : `Add a ${itemLabel.toLowerCase()} and select a collection for it.`,
32202
32304
  action: /* @__PURE__ */ React26__default.createElement(Link2, {
32203
32305
  href: activeCategoryId ? vendorProductCreateUrl(activeCategoryId, {
@@ -32208,34 +32310,32 @@ function VendorCategoryWorkspacePage() {
32208
32310
  }
32209
32311
  }))));
32210
32312
  }
32211
- var CATEGORY_PRODUCT_HIDDEN_FIELDS, CATEGORY_PRODUCT_EXTRA_COLUMNS;
32313
+ var CATEGORY_PRODUCT_HIDDEN_FIELDS, VENDOR_EXTRA_COLUMN, EVENT_EXTRA_COLUMN;
32212
32314
  var init_VendorCategoryWorkspacePage = __esm({
32213
32315
  "src/admin/pages/VendorCategoryWorkspacePage.tsx"() {
32214
32316
  "use client";
32215
32317
  init_vendor_scope();
32216
32318
  init_CRUD();
32217
32319
  init_store_crud_configs();
32320
+ init_admin_config_context();
32218
32321
  init_use_catalog_categories();
32219
32322
  init_category_item_label();
32220
32323
  CATEGORY_PRODUCT_HIDDEN_FIELDS = /* @__PURE__ */ new Set([
32221
32324
  "categoryId"
32222
32325
  ]);
32223
- CATEGORY_PRODUCT_EXTRA_COLUMNS = [
32224
- {
32225
- field: "vendorId",
32226
- displayName: "Vendor",
32227
- relationApi: "/api/vendors",
32228
- relationLabelField: "name",
32229
- relationValueField: "id"
32230
- },
32231
- {
32232
- field: "eventName",
32233
- displayName: "Event"
32234
- }
32235
- ];
32326
+ VENDOR_EXTRA_COLUMN = {
32327
+ field: "vendorId",
32328
+ displayName: "Vendor",
32329
+ relationApi: "/api/vendors",
32330
+ relationLabelField: "name",
32331
+ relationValueField: "id"
32332
+ };
32333
+ EVENT_EXTRA_COLUMN = {
32334
+ field: "eventName",
32335
+ displayName: "Event"
32336
+ };
32236
32337
  __name(buildAdminProductColumns, "buildAdminProductColumns");
32237
- __name(buildAdminAllProductColumns, "buildAdminAllProductColumns");
32238
- __name(buildVendorProductColumns, "buildVendorProductColumns");
32338
+ __name(buildAllProductColumns, "buildAllProductColumns");
32239
32339
  __name(withCollectionRelationApi, "withCollectionRelationApi");
32240
32340
  __name(VendorCategoryWorkspacePage, "VendorCategoryWorkspacePage");
32241
32341
  }
@@ -32250,7 +32350,52 @@ function CollectionsWorkspacePage() {
32250
32350
  const { data: session } = useSession();
32251
32351
  const vendorPortal = isVendorPortalUser(session?.user);
32252
32352
  const isCatalog = !vendorPortal;
32253
- const collectionColumns = useMemo(() => STORE_CRUD_CONFIGS.collections.columns.filter((c) => c.field !== "vendorId"), []);
32353
+ const { multiVendorEnabled } = useContext(AdminConfigContext);
32354
+ const [vendorOptions, setVendorOptions] = useState([]);
32355
+ useEffect(() => {
32356
+ if (vendorPortal || multiVendorEnabled === false) return;
32357
+ fetch("/api/vendors?limit=500").then((r) => r.ok ? r.json() : null).then((data) => {
32358
+ if (!data?.data?.length) return;
32359
+ setVendorOptions(data.data.map((v) => ({
32360
+ value: String(v.id),
32361
+ label: v.name
32362
+ })));
32363
+ }).catch(() => {
32364
+ });
32365
+ }, [
32366
+ vendorPortal,
32367
+ multiVendorEnabled
32368
+ ]);
32369
+ const showVendorColumn = multiVendorEnabled !== false && !vendorPortal;
32370
+ const collectionColumns = useMemo(() => {
32371
+ const base = STORE_CRUD_CONFIGS.collections.columns.filter((c) => c.field !== "vendorId");
32372
+ return showVendorColumn ? [
32373
+ VENDOR_COLUMN,
32374
+ ...base
32375
+ ] : base;
32376
+ }, [
32377
+ showVendorColumn
32378
+ ]);
32379
+ const collectionFilters = useMemo(() => {
32380
+ if (!showVendorColumn || vendorOptions.length <= 1) return void 0;
32381
+ return [
32382
+ {
32383
+ param: "vendorId",
32384
+ label: "Vendor",
32385
+ type: "select",
32386
+ options: [
32387
+ {
32388
+ value: "",
32389
+ label: "All vendors"
32390
+ },
32391
+ ...vendorOptions
32392
+ ]
32393
+ }
32394
+ ];
32395
+ }, [
32396
+ showVendorColumn,
32397
+ vendorOptions
32398
+ ]);
32254
32399
  const listParams = useMemo(() => isCatalog ? {
32255
32400
  isCatalog: "true"
32256
32401
  } : void 0, [
@@ -32266,20 +32411,32 @@ function CollectionsWorkspacePage() {
32266
32411
  title: "Collections",
32267
32412
  apiEndpoint: "/api/collections",
32268
32413
  columns: collectionColumns,
32269
- filterColumns: STORE_CRUD_CONFIGS.collections.columns,
32414
+ filterColumns: collectionColumns,
32270
32415
  addEditPageUrl: "/admin/collections",
32271
32416
  createQueryParams,
32272
32417
  defaultSortField: "sortOrder",
32273
32418
  defaultSortOrder: "asc",
32274
- extraListParams: listParams
32419
+ extraListParams: listParams,
32420
+ filters: collectionFilters
32275
32421
  });
32276
32422
  }
32423
+ var VENDOR_COLUMN;
32277
32424
  var init_CollectionsWorkspacePage = __esm({
32278
32425
  "src/admin/pages/CollectionsWorkspacePage.tsx"() {
32279
32426
  "use client";
32280
32427
  init_vendor_scope();
32281
32428
  init_CRUD();
32282
32429
  init_store_crud_configs();
32430
+ init_admin_config_context();
32431
+ VENDOR_COLUMN = {
32432
+ field: "vendorId",
32433
+ displayName: "Vendor",
32434
+ hideInCreate: true,
32435
+ hideInEdit: true,
32436
+ relationApi: "/api/vendors",
32437
+ relationLabelField: "name",
32438
+ relationValueField: "id"
32439
+ };
32283
32440
  __name(CollectionsWorkspacePage, "CollectionsWorkspacePage");
32284
32441
  }
32285
32442
  });
@@ -36191,7 +36348,7 @@ function AdminPageResolver({ slug }) {
36191
36348
  const searchParams = useSearchParams();
36192
36349
  const { data: session } = useSession();
36193
36350
  const vendorPortal = isVendorPortalUser(session?.user);
36194
- const { customCrudConfigs, storeEnabled } = useContext(AdminConfigContext);
36351
+ const { customCrudConfigs, storeEnabled, multiVendorEnabled, eventsEnabled } = useContext(AdminConfigContext);
36195
36352
  const key = slug?.[0] || "dashboard";
36196
36353
  const [vendorOptions, setVendorOptions] = useState([]);
36197
36354
  useEffect(() => {
@@ -36217,17 +36374,21 @@ function AdminPageResolver({ slug }) {
36217
36374
  if (!config) return void 0;
36218
36375
  let columns = config.columns;
36219
36376
  let filters = config.filters ?? [];
36220
- if (vendorPortal) {
36377
+ if (vendorPortal || multiVendorEnabled === false) {
36221
36378
  columns = columns.filter((column) => column.field !== "vendorId");
36222
36379
  filters = filters.filter((filter) => filter.param !== "vendorId");
36223
36380
  }
36224
- if (!vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "product_categories" && key !== "event_products" && !columns.some((c) => c.field === "vendorId")) {
36381
+ if (eventsEnabled === false) {
36382
+ columns = columns.filter((column) => column.field !== "eventId" && column.field !== "eventName");
36383
+ filters = filters.filter((filter) => filter.param !== "eventId");
36384
+ }
36385
+ if (multiVendorEnabled !== false && !vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "event_products" && !columns.some((c) => c.field === "vendorId")) {
36225
36386
  columns = [
36226
- VENDOR_COLUMN,
36387
+ VENDOR_COLUMN2,
36227
36388
  ...columns
36228
36389
  ];
36229
36390
  }
36230
- if (!vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "product_categories" && key !== "event_products" && vendorOptions.length > 1 && !filters.some((f) => f.param === "vendorId")) {
36391
+ if (multiVendorEnabled !== false && !vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "event_products" && vendorOptions.length > 1 && !filters.some((f) => f.param === "vendorId")) {
36231
36392
  filters = [
36232
36393
  {
36233
36394
  param: "vendorId",
@@ -36256,7 +36417,9 @@ function AdminPageResolver({ slug }) {
36256
36417
  key,
36257
36418
  customCrudConfigs,
36258
36419
  vendorOptions,
36259
- vendorPortal
36420
+ vendorPortal,
36421
+ multiVendorEnabled,
36422
+ eventsEnabled
36260
36423
  ]);
36261
36424
  const isContactsWithStore = key === "contacts" && storeEnabled;
36262
36425
  const extraListParams = useMemo(() => isContactsWithStore ? {
@@ -36284,6 +36447,20 @@ function AdminPageResolver({ slug }) {
36284
36447
  crud,
36285
36448
  isContactsWithStore
36286
36449
  ]);
36450
+ const isVendorRelated = useMemo(() => {
36451
+ return key === "vendors" || key === "vendor-team" || key === "vendor-roles" || key === "vendor-profile" || key === "store" || key === "analytics" || key === "vendor_users" || key === "vendor_role_permissions";
36452
+ }, [
36453
+ key
36454
+ ]);
36455
+ useEffect(() => {
36456
+ if (multiVendorEnabled === false && isVendorRelated) {
36457
+ router.replace("/admin/access-denied");
36458
+ }
36459
+ }, [
36460
+ multiVendorEnabled,
36461
+ isVendorRelated,
36462
+ router
36463
+ ]);
36287
36464
  useEffect(() => {
36288
36465
  if (key === "layout-settings") {
36289
36466
  router.replace("/admin/settings?tab=navbar");
@@ -36301,6 +36478,34 @@ function AdminPageResolver({ slug }) {
36301
36478
  router,
36302
36479
  vendorPortal
36303
36480
  ]);
36481
+ const isEventsRelated = key === "events";
36482
+ useEffect(() => {
36483
+ if (eventsEnabled === false && isEventsRelated) {
36484
+ router.replace("/admin/access-denied");
36485
+ }
36486
+ }, [
36487
+ eventsEnabled,
36488
+ isEventsRelated,
36489
+ router
36490
+ ]);
36491
+ if (multiVendorEnabled === false && isVendorRelated) {
36492
+ return /* @__PURE__ */ React26__default.createElement("div", {
36493
+ className: "flex justify-center py-8"
36494
+ }, /* @__PURE__ */ React26__default.createElement("div", {
36495
+ className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
36496
+ }), /* @__PURE__ */ React26__default.createElement("span", {
36497
+ className: "ml-2"
36498
+ }, "Redirecting\u2026"));
36499
+ }
36500
+ if (eventsEnabled === false && isEventsRelated) {
36501
+ return /* @__PURE__ */ React26__default.createElement("div", {
36502
+ className: "flex justify-center py-8"
36503
+ }, /* @__PURE__ */ React26__default.createElement("div", {
36504
+ className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
36505
+ }), /* @__PURE__ */ React26__default.createElement("span", {
36506
+ className: "ml-2"
36507
+ }, "Redirecting\u2026"));
36508
+ }
36304
36509
  if (key === "layout-settings") {
36305
36510
  return /* @__PURE__ */ React26__default.createElement("div", {
36306
36511
  className: "flex justify-center py-8"
@@ -36597,7 +36802,7 @@ function AdminPageResolver({ slug }) {
36597
36802
  className: "text-gray-500"
36598
36803
  }, "Page not found"));
36599
36804
  }
36600
- 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;
36805
+ 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;
36601
36806
  var init_AdminPageResolver = __esm({
36602
36807
  "src/admin/pages/AdminPageResolver.tsx"() {
36603
36808
  "use client";
@@ -36930,7 +37135,7 @@ var init_AdminPageResolver = __esm({
36930
37135
  }
36931
37136
  };
36932
37137
  __name(BlogEditorWrapper, "BlogEditorWrapper");
36933
- VENDOR_COLUMN = {
37138
+ VENDOR_COLUMN2 = {
36934
37139
  field: "vendorId",
36935
37140
  displayName: "Vendor",
36936
37141
  hideInCreate: true,
@@ -37176,21 +37381,21 @@ function EventDetailPage({ eventId }) {
37176
37381
  }, /* @__PURE__ */ React.createElement("dl", {
37177
37382
  className: "grid gap-4 sm:grid-cols-2"
37178
37383
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37179
- className: labelCls8
37384
+ className: labelCls7
37180
37385
  }, "Name"), /* @__PURE__ */ React.createElement("dd", {
37181
37386
  className: valueCls
37182
37387
  }, displayValue(event.name))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37183
- className: labelCls8
37388
+ className: labelCls7
37184
37389
  }, "Slug"), /* @__PURE__ */ React.createElement("dd", {
37185
37390
  className: valueCls
37186
37391
  }, displayValue(event.slug))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37187
- className: labelCls8
37392
+ className: labelCls7
37188
37393
  }, "Sort order"), /* @__PURE__ */ React.createElement("dd", {
37189
37394
  className: valueCls
37190
37395
  }, event.sortOrder)), /* @__PURE__ */ React.createElement("div", {
37191
37396
  className: "sm:col-span-2"
37192
37397
  }, /* @__PURE__ */ React.createElement("dt", {
37193
- className: labelCls8
37398
+ className: labelCls7
37194
37399
  }, "Description"), /* @__PURE__ */ React.createElement("dd", {
37195
37400
  className: `${valueCls} prose prose-sm max-w-none`,
37196
37401
  dangerouslySetInnerHTML: {
@@ -37199,11 +37404,11 @@ function EventDetailPage({ eventId }) {
37199
37404
  })), /* @__PURE__ */ React.createElement("div", {
37200
37405
  className: "sm:col-span-2"
37201
37406
  }, /* @__PURE__ */ React.createElement("dt", {
37202
- className: labelCls8
37407
+ className: labelCls7
37203
37408
  }, "Entity types"), /* @__PURE__ */ React.createElement("dd", {
37204
37409
  className: valueCls
37205
37410
  }, event.entityTypes?.length ? event.entityTypes.map(formatEventEntityTypeLabel).join(", ") : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37206
- className: labelCls8
37411
+ className: labelCls7
37207
37412
  }, "Banner image"), /* @__PURE__ */ React.createElement("dd", {
37208
37413
  className: valueCls
37209
37414
  }, event.bannerImageUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37212,7 +37417,7 @@ function EventDetailPage({ eventId }) {
37212
37417
  rel: "noreferrer",
37213
37418
  className: "text-blue-600 hover:underline break-all"
37214
37419
  }, event.bannerImageUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37215
- className: labelCls8
37420
+ className: labelCls7
37216
37421
  }, "Logo"), /* @__PURE__ */ React.createElement("dd", {
37217
37422
  className: valueCls
37218
37423
  }, event.logoUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37221,11 +37426,11 @@ function EventDetailPage({ eventId }) {
37221
37426
  rel: "noreferrer",
37222
37427
  className: "text-blue-600 hover:underline break-all"
37223
37428
  }, event.logoUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37224
- className: labelCls8
37429
+ className: labelCls7
37225
37430
  }, "Pricing type"), /* @__PURE__ */ React.createElement("dd", {
37226
37431
  className: valueCls
37227
37432
  }, event.pricingType ? event.pricingType.charAt(0).toUpperCase() + event.pricingType.slice(1) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37228
- className: labelCls8
37433
+ className: labelCls7
37229
37434
  }, "Mode"), /* @__PURE__ */ React.createElement("dd", {
37230
37435
  className: valueCls
37231
37436
  }, formatMode(event.entityMode))))) : activeTab === "venue" ? /* @__PURE__ */ React.createElement("section", {
@@ -37235,21 +37440,21 @@ function EventDetailPage({ eventId }) {
37235
37440
  }, /* @__PURE__ */ React.createElement("div", {
37236
37441
  className: "sm:col-span-2"
37237
37442
  }, /* @__PURE__ */ React.createElement("dt", {
37238
- className: labelCls8
37443
+ className: labelCls7
37239
37444
  }, "Venue"), /* @__PURE__ */ React.createElement("dd", {
37240
37445
  className: valueCls
37241
37446
  }, displayValue(event.venue))), event.additionalVenueDetails ? /* @__PURE__ */ React.createElement("div", {
37242
37447
  className: "sm:col-span-2"
37243
37448
  }, /* @__PURE__ */ React.createElement("dt", {
37244
- className: labelCls8
37449
+ className: labelCls7
37245
37450
  }, "Additional venue details"), /* @__PURE__ */ React.createElement("dd", {
37246
37451
  className: `${valueCls} whitespace-pre-wrap`
37247
37452
  }, event.additionalVenueDetails)) : null, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37248
- className: labelCls8
37453
+ className: labelCls7
37249
37454
  }, "City"), /* @__PURE__ */ React.createElement("dd", {
37250
37455
  className: valueCls
37251
37456
  }, displayValue(event.city ?? event.cityCountry?.split(",")[0]?.trim()))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37252
- className: labelCls8
37457
+ className: labelCls7
37253
37458
  }, "Country"), /* @__PURE__ */ React.createElement("dd", {
37254
37459
  className: valueCls
37255
37460
  }, displayValue(event.country ?? (event.cityCountry?.includes(",") ? event.cityCountry.split(",").slice(1).join(",").trim() : null)))))) : activeTab === "datetime" ? /* @__PURE__ */ React.createElement("section", {
@@ -37257,29 +37462,29 @@ function EventDetailPage({ eventId }) {
37257
37462
  }, /* @__PURE__ */ React.createElement("dl", {
37258
37463
  className: "grid gap-4 sm:grid-cols-2"
37259
37464
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37260
- className: labelCls8
37465
+ className: labelCls7
37261
37466
  }, "Timezone"), /* @__PURE__ */ React.createElement("dd", {
37262
37467
  className: valueCls
37263
37468
  }, displayValue(event.timezone))), /* @__PURE__ */ React.createElement("div", null), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37264
- className: labelCls8
37469
+ className: labelCls7
37265
37470
  }, "Event start"), /* @__PURE__ */ React.createElement("dd", {
37266
37471
  className: valueCls
37267
37472
  }, event.startDate ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, startFormatted.dateLine), startFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37268
37473
  className: "text-gray-600"
37269
37474
  }, startFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37270
- className: labelCls8
37475
+ className: labelCls7
37271
37476
  }, "Event end"), /* @__PURE__ */ React.createElement("dd", {
37272
37477
  className: valueCls
37273
37478
  }, event.endDate ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, endFormatted.dateLine), endFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37274
37479
  className: "text-gray-600"
37275
37480
  }, endFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37276
- className: labelCls8
37481
+ className: labelCls7
37277
37482
  }, "Registration opens"), /* @__PURE__ */ React.createElement("dd", {
37278
37483
  className: valueCls
37279
37484
  }, event.registrationOpensAt ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, regOpensFormatted.dateLine), regOpensFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
37280
37485
  className: "text-gray-600"
37281
37486
  }, regOpensFormatted.timeLine) : null) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37282
- className: labelCls8
37487
+ className: labelCls7
37283
37488
  }, "Registration closes"), /* @__PURE__ */ React.createElement("dd", {
37284
37489
  className: valueCls
37285
37490
  }, event.registrationClosesAt ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", null, regClosesFormatted.dateLine), regClosesFormatted.timeLine ? /* @__PURE__ */ React.createElement("div", {
@@ -37293,15 +37498,15 @@ function EventDetailPage({ eventId }) {
37293
37498
  }, "Checkout & website"), /* @__PURE__ */ React.createElement("dl", {
37294
37499
  className: "grid gap-4 sm:grid-cols-2"
37295
37500
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37296
- className: labelCls8
37501
+ className: labelCls7
37297
37502
  }, "Default currency"), /* @__PURE__ */ React.createElement("dd", {
37298
37503
  className: valueCls
37299
37504
  }, displayValue(event.defaultCurrency))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37300
- className: labelCls8
37505
+ className: labelCls7
37301
37506
  }, "Supported currencies"), /* @__PURE__ */ React.createElement("dd", {
37302
37507
  className: valueCls
37303
37508
  }, event.supportedCurrencies?.length ? event.supportedCurrencies.join(", ") : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37304
- className: labelCls8
37509
+ className: labelCls7
37305
37510
  }, "Website"), /* @__PURE__ */ React.createElement("dd", {
37306
37511
  className: valueCls
37307
37512
  }, event.officialWebsiteUrl ? /* @__PURE__ */ React.createElement("a", {
@@ -37310,13 +37515,13 @@ function EventDetailPage({ eventId }) {
37310
37515
  rel: "noreferrer",
37311
37516
  className: "text-blue-600 hover:underline break-all"
37312
37517
  }, event.officialWebsiteUrl) : "\u2014")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37313
- className: labelCls8
37518
+ className: labelCls7
37314
37519
  }, "Support contact"), /* @__PURE__ */ React.createElement("dd", {
37315
37520
  className: valueCls
37316
37521
  }, displayValue(event.supportContact))), /* @__PURE__ */ React.createElement("div", {
37317
37522
  className: "sm:col-span-2"
37318
37523
  }, /* @__PURE__ */ React.createElement("dt", {
37319
- className: labelCls8
37524
+ className: labelCls7
37320
37525
  }, "Contact form"), /* @__PURE__ */ React.createElement("dd", {
37321
37526
  className: valueCls
37322
37527
  }, event.contactFormId != null ? /* @__PURE__ */ React.createElement(Link2, {
@@ -37325,7 +37530,7 @@ function EventDetailPage({ eventId }) {
37325
37530
  }, contactFormLabel ?? `Form #${event.contactFormId}`) : "\u2014")), /* @__PURE__ */ React.createElement("div", {
37326
37531
  className: "sm:col-span-2 grid gap-4 sm:grid-cols-2 sm:items-end"
37327
37532
  }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("dt", {
37328
- className: labelCls8
37533
+ className: labelCls7
37329
37534
  }, "Max group quantity"), /* @__PURE__ */ React.createElement("dd", {
37330
37535
  className: valueCls
37331
37536
  }, event.maxGroupPurchaseQuantity != null ? event.maxGroupPurchaseQuantity : "\u2014")), /* @__PURE__ */ React.createElement("div", {
@@ -37334,13 +37539,7 @@ function EventDetailPage({ eventId }) {
37334
37539
  className: valueCls
37335
37540
  }, event.allowGroupOrders ? "Group orders allowed" : "Group orders disabled"), /* @__PURE__ */ React.createElement("dd", {
37336
37541
  className: valueCls
37337
- }, event.sendIndividualTicketPDFToAttendees ? "Individual ticket PDFs sent to attendees" : "Individual ticket PDFs not sent"))), /* @__PURE__ */ React.createElement("div", {
37338
- className: "sm:col-span-2"
37339
- }, /* @__PURE__ */ React.createElement("dd", {
37340
- className: valueCls
37341
- }, /* @__PURE__ */ React.createElement(EventNotificationSummary, {
37342
- eventId: String(event.id)
37343
- }))))), event.socialMediaLinks && Object.keys(event.socialMediaLinks).length > 0 ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("h2", {
37542
+ }, 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", {
37344
37543
  className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-3"
37345
37544
  }, "Social media"), /* @__PURE__ */ React.createElement(SocialMediaLinksDisplay, {
37346
37545
  links: event.socialMediaLinks,
@@ -37352,7 +37551,7 @@ function EventDetailPage({ eventId }) {
37352
37551
  }))
37353
37552
  }));
37354
37553
  }
37355
- var sectionCls7, labelCls8, valueCls;
37554
+ var sectionCls7, labelCls7, valueCls;
37356
37555
  var init_EventDetailPage = __esm({
37357
37556
  "src/admin/pages/EventDetailPage.tsx"() {
37358
37557
  "use client";
@@ -37364,9 +37563,8 @@ var init_EventDetailPage = __esm({
37364
37563
  init_DetailPageLayout();
37365
37564
  init_DetailPageHeader();
37366
37565
  init_EventProductsSection();
37367
- init_EventNotificationSettings();
37368
37566
  sectionCls7 = "border border-gray-200 rounded-lg p-4 bg-gray-50/50";
37369
- labelCls8 = "text-xs font-medium text-gray-500";
37567
+ labelCls7 = "text-xs font-medium text-gray-500";
37370
37568
  valueCls = "text-sm text-gray-900 mt-0.5";
37371
37569
  __name(displayValue, "displayValue");
37372
37570
  __name(formatMode, "formatMode");