@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.
- package/dist/admin.cjs +1222 -1024
- package/dist/admin.d.cts +6 -0
- package/dist/admin.d.ts +6 -0
- package/dist/admin.js +1224 -1026
- package/dist/api.cjs +40 -39
- package/dist/api.js +8 -7
- package/dist/auth.cjs +51 -51
- package/dist/auth.d.cts +3 -3
- package/dist/auth.d.ts +3 -3
- package/dist/auth.js +3 -3
- package/dist/chunk-22FFHLTO.cjs +2356 -0
- package/dist/{chunk-CNTSLED2.cjs → chunk-E6WVP7BK.cjs} +75 -14
- package/dist/chunk-HCIRL37O.js +21 -0
- package/dist/chunk-HT5DI3XW.cjs +82 -0
- package/dist/{chunk-EF2JBPDM.js → chunk-KFFB6EMZ.js} +9 -0
- package/dist/chunk-NNQBWDCI.js +2325 -0
- package/dist/{chunk-TIAEXJLI.cjs → chunk-OIGCAGH7.cjs} +7 -7
- package/dist/{chunk-4TRPKBKO.js → chunk-P7QCLE5W.js} +52 -24
- package/dist/{chunk-2XE4X74C.js → chunk-PYUXVU75.js} +7801 -6871
- package/dist/{chunk-EQPITOP6.js → chunk-SBRBR3VO.js} +70 -9
- package/dist/{chunk-N44BJZ4C.cjs → chunk-SPQFNIYJ.cjs} +9 -0
- package/dist/chunk-UCKN4BBY.cjs +24 -0
- package/dist/{chunk-6KPQWRFW.js → chunk-UXMDSNIG.js} +1 -1
- package/dist/{chunk-BGJAV67S.cjs → chunk-VJDUKAJ3.cjs} +8207 -7261
- package/dist/{chunk-3KPNTQBV.cjs → chunk-WMXPKKXU.cjs} +52 -23
- package/dist/chunk-X47PBV4I.js +79 -0
- package/dist/cli.cjs +4 -2
- package/dist/cli.js +4 -2
- package/dist/emit-order-notification-trigger-D2N3KFHL.cjs +16 -0
- package/dist/emit-order-notification-trigger-IVLWKKJL.js +3 -0
- package/dist/{event-order-defaults-DUGDVGJI.cjs → event-order-defaults-EMWBIGL3.cjs} +9 -9
- package/dist/{event-order-defaults-6E543227.js → event-order-defaults-SDRNAZHC.js} +1 -1
- package/dist/index.cjs +805 -1059
- package/dist/index.d.cts +834 -728
- package/dist/index.d.ts +834 -728
- package/dist/index.js +385 -724
- package/dist/migrations/1775500000000-RssFeedsAndArticles.ts +0 -1
- package/dist/migrations/1775700000000-JobSchedules.ts +0 -1
- package/dist/migrations/1781220000000-AddWhatsappTriggerBindings.ts +23 -0
- package/dist/migrations/1781230000000-AddOrderNotificationTriggers.ts +46 -0
- package/dist/migrations/1781240000000-DropEventOrderNotificationColumns.ts +29 -0
- package/dist/migrations/1781250000000-RemoveOrderRefundedTrigger.ts +36 -0
- package/dist/migrations/1781260000000-RenameWhatsappTriggerBindingsToOrderNotificationBindings.ts +92 -0
- package/dist/migrations/1781270000000-ComboVendorId.ts +58 -0
- package/dist/order-notification-dispatcher-RU7BTGGX.cjs +18 -0
- package/dist/order-notification-dispatcher-XWIJYDGA.js +5 -0
- package/dist/{rbac-debug-db-D7ME7QUY.cjs → rbac-debug-db-KHG4FJC3.cjs} +2 -2
- package/dist/{rbac-debug-db-MTCTVNNM.js → rbac-debug-db-QWHOENBR.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-46GKADYE.cjs +0 -84
- package/dist/chunk-7YIBMQDR.cjs +0 -86
- package/dist/chunk-J7XHLOLO.js +0 -830
- package/dist/chunk-JBRR5UYL.js +0 -87
- package/dist/chunk-JHF4YYRC.cjs +0 -188
- package/dist/chunk-PAMVINEX.cjs +0 -577
- package/dist/chunk-QM733NUK.js +0 -186
- package/dist/chunk-R73BKDRO.cjs +0 -90
- package/dist/chunk-TFUOHI37.cjs +0 -839
- package/dist/chunk-XDSNZUW7.js +0 -564
- package/dist/chunk-ZQ4X6OAU.js +0 -82
- package/dist/chunk-ZSVCP6N3.js +0 -83
- package/dist/email-FKR4FXFI.js +0 -5
- package/dist/email-KVKVPNCL.cjs +0 -58
- package/dist/event-order-notifications-5GSAOYVS.cjs +0 -27
- package/dist/event-order-notifications-IIIF23D5.js +0 -10
- package/dist/layout-36UFTHC5.cjs +0 -11
- package/dist/layout-AOBN26XG.js +0 -2
- package/dist/whatsapp-queue-3DXA4MXU.js +0 -2
- package/dist/whatsapp-queue-KG65MXD5.cjs +0 -15
package/dist/admin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useSession,
|
|
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,
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
})))),
|
|
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,
|
|
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: "
|
|
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
|
-
|
|
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
|
|
11047
|
-
type: "
|
|
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.")))),
|
|
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
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
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
|
-
"
|
|
14377
|
+
"customerName",
|
|
14378
|
+
"customerPhone",
|
|
14379
|
+
"total",
|
|
14160
14380
|
"currency",
|
|
14161
|
-
"
|
|
14162
|
-
"
|
|
14163
|
-
"trackUrl"
|
|
14381
|
+
"vendorId",
|
|
14382
|
+
"refundAmount"
|
|
14164
14383
|
];
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
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
|
|
14186
|
-
|
|
14187
|
-
|
|
14188
|
-
|
|
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
|
|
14192
|
-
const
|
|
14193
|
-
|
|
14194
|
-
|
|
14195
|
-
|
|
14196
|
-
|
|
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
|
|
14199
|
-
|
|
14200
|
-
|
|
14201
|
-
|
|
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
|
-
|
|
14779
|
+
templates
|
|
14205
14780
|
]);
|
|
14206
14781
|
useEffect(() => {
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
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
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
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
|
-
},
|
|
14817
|
+
}, "Order trigger emails"), /* @__PURE__ */ React.createElement("p", {
|
|
14220
14818
|
className: "text-xs text-gray-500 dark:text-gray-400 mt-1"
|
|
14221
|
-
},
|
|
14222
|
-
className: "
|
|
14223
|
-
}, /* @__PURE__ */ React.createElement("
|
|
14224
|
-
className: "
|
|
14225
|
-
},
|
|
14226
|
-
className: "
|
|
14227
|
-
},
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
|
|
14232
|
-
|
|
14233
|
-
|
|
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
|
|
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(
|
|
14241
|
-
|
|
14242
|
-
|
|
14243
|
-
|
|
14244
|
-
|
|
14245
|
-
|
|
14246
|
-
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
|
|
14250
|
-
|
|
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
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
className: "h-8 text-sm"
|
|
14261
|
-
}))
|
|
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
|
-
},
|
|
14266
|
-
|
|
14267
|
-
|
|
14268
|
-
|
|
14269
|
-
|
|
14270
|
-
|
|
14271
|
-
|
|
14272
|
-
className: "text-sm font-mono"
|
|
14273
|
-
})),
|
|
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
|
-
}, "
|
|
14278
|
-
|
|
14279
|
-
|
|
14280
|
-
|
|
14281
|
-
|
|
14282
|
-
|
|
14283
|
-
|
|
14284
|
-
className: "
|
|
14285
|
-
}))
|
|
14286
|
-
|
|
14287
|
-
|
|
14288
|
-
|
|
14289
|
-
|
|
14290
|
-
|
|
14291
|
-
|
|
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
|
-
|
|
15011
|
+
init_button();
|
|
14316
15012
|
init_input();
|
|
14317
15013
|
init_textarea();
|
|
14318
|
-
|
|
14319
|
-
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
|
|
14323
|
-
|
|
14324
|
-
|
|
14325
|
-
|
|
14326
|
-
|
|
14327
|
-
|
|
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
|
-
|
|
14331
|
-
|
|
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
|
|
14352
|
-
|
|
14353
|
-
|
|
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
|
-
|
|
14372
|
-
|
|
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
|
-
}, "
|
|
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,
|
|
14395
|
-
|
|
14396
|
-
|
|
14397
|
-
|
|
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
|
-
}, "
|
|
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"))),
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
30600
|
+
labelClassName: labelCls6
|
|
30437
30601
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
30438
|
-
className:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
}))
|
|
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,
|
|
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
|
-
|
|
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
|
|
30847
|
+
async function fetchEventDefaultCurrency(eventId) {
|
|
30691
30848
|
try {
|
|
30692
30849
|
const res = await fetch(`/api/events/${eventId}`);
|
|
30693
|
-
if (!res.ok) return
|
|
30850
|
+
if (!res.ok) return "INR";
|
|
30694
30851
|
const data = await res.json();
|
|
30695
|
-
|
|
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
|
|
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 [
|
|
30751
|
-
const [
|
|
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
|
-
|
|
30909
|
+
setDefaultCurrency("INR");
|
|
30775
30910
|
return;
|
|
30776
30911
|
}
|
|
30777
30912
|
let cancelled = false;
|
|
30778
|
-
|
|
30779
|
-
if (!cancelled)
|
|
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
|
-
|
|
30880
|
-
|
|
30881
|
-
|
|
30882
|
-
|
|
30883
|
-
|
|
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 (!
|
|
31105
|
+
if (!priceStr.trim()) {
|
|
30979
31106
|
setErrors([
|
|
30980
|
-
|
|
31107
|
+
`Price (${defaultCurrency}) is required`
|
|
30981
31108
|
]);
|
|
30982
31109
|
return;
|
|
30983
31110
|
}
|
|
30984
|
-
const
|
|
30985
|
-
if (!
|
|
31111
|
+
const price = Number(priceStr);
|
|
31112
|
+
if (!Number.isFinite(price) || price < 0) {
|
|
30986
31113
|
setErrors([
|
|
30987
|
-
|
|
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
|
|
31036
|
-
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
|
-
},
|
|
31204
|
-
|
|
31205
|
-
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
|
|
31210
|
-
|
|
31211
|
-
|
|
31212
|
-
|
|
31213
|
-
|
|
31214
|
-
|
|
31215
|
-
}
|
|
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
|
|
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
|
-
|
|
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
|
-
...
|
|
32189
|
+
...extraColumns,
|
|
32066
32190
|
...cols
|
|
32067
32191
|
];
|
|
32068
32192
|
return [
|
|
32069
32193
|
...cols.slice(0, nameIdx + 1),
|
|
32070
|
-
...
|
|
32194
|
+
...extraColumns,
|
|
32071
32195
|
...cols.slice(nameIdx + 1)
|
|
32072
32196
|
];
|
|
32073
32197
|
}
|
|
32074
|
-
function
|
|
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
|
-
...
|
|
32210
|
+
...extraColumns,
|
|
32079
32211
|
...cols
|
|
32080
32212
|
];
|
|
32081
32213
|
return [
|
|
32082
32214
|
...cols.slice(0, nameIdx + 1),
|
|
32083
|
-
...
|
|
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 = !
|
|
32133
|
-
const workspaceFrom = activeCategoryId ?
|
|
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 =
|
|
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
|
-
|
|
32159
|
-
|
|
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
|
-
|
|
32196
|
-
includeEventNames: "1"
|
|
32197
|
-
} : {}
|
|
32299
|
+
includeEventNames: "1"
|
|
32198
32300
|
},
|
|
32199
32301
|
emptyState: {
|
|
32200
|
-
title: showAllProducts ? "No products found" : `No ${activeCategory
|
|
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,
|
|
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
|
-
|
|
32224
|
-
|
|
32225
|
-
|
|
32226
|
-
|
|
32227
|
-
|
|
32228
|
-
|
|
32229
|
-
|
|
32230
|
-
|
|
32231
|
-
|
|
32232
|
-
|
|
32233
|
-
|
|
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(
|
|
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
|
|
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:
|
|
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 (
|
|
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
|
-
|
|
36387
|
+
VENDOR_COLUMN2,
|
|
36227
36388
|
...columns
|
|
36228
36389
|
];
|
|
36229
36390
|
}
|
|
36230
|
-
if (!vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "
|
|
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,
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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");
|