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