@infuro/cms-core 1.0.71 → 1.0.73
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 +523 -133
- package/dist/admin.d.cts +1 -0
- package/dist/admin.d.ts +1 -0
- package/dist/admin.js +525 -135
- package/dist/api.cjs +33 -33
- package/dist/api.d.cts +13 -6
- package/dist/api.d.ts +13 -6
- package/dist/api.js +1 -1
- package/dist/auth.cjs +11 -11
- package/dist/auth.d.cts +15 -0
- package/dist/auth.d.ts +15 -0
- package/dist/auth.js +1 -1
- package/dist/{chunk-7NQMGB2S.js → chunk-4LF5OGBF.js} +2557 -2101
- package/dist/{chunk-SCE2GIKH.js → chunk-DEGN4BTH.js} +9 -0
- package/dist/{chunk-CKTRA3Q2.cjs → chunk-F3FKBNMQ.cjs} +9 -0
- package/dist/{chunk-OP624LWU.cjs → chunk-HQ3A43HO.cjs} +2556 -2100
- package/dist/index.cjs +217 -217
- package/dist/index.d.cts +31 -9
- package/dist/index.d.ts +31 -9
- package/dist/index.js +3 -3
- package/dist/migrations/1783400000000-MakeProductConfigTaxIdNullable.ts +40 -0
- package/dist/migrations/helpers/vendor-role-seed.ts +65 -27
- package/package.json +1 -1
package/dist/admin.cjs
CHANGED
|
@@ -381,9 +381,8 @@ var init_vendor_scope = __esm({
|
|
|
381
381
|
}
|
|
382
382
|
});
|
|
383
383
|
function AdminHeader() {
|
|
384
|
-
const { data: session } = react.useSession();
|
|
384
|
+
const { data: session, update } = react.useSession();
|
|
385
385
|
const sessionUser = session?.user;
|
|
386
|
-
const roleLabel = sessionUser?.groupName?.trim() || (sessionUser?.isRBACAdmin ? "Administrator" : "Admin user");
|
|
387
386
|
const isVendor = isVendorPortalUser(sessionUser);
|
|
388
387
|
const isMobile = useIsMobile();
|
|
389
388
|
const configuredLogo = process.env.NEXT_PUBLIC_ADMIN_LOGO_URL || DEFAULT_ADMIN_LOGO;
|
|
@@ -392,9 +391,125 @@ function AdminHeader() {
|
|
|
392
391
|
const isDataLogo = React26.useMemo(() => logoSrc.startsWith("data:"), [
|
|
393
392
|
logoSrc
|
|
394
393
|
]);
|
|
394
|
+
const [isSwitching, setIsSwitching] = React26.useState(false);
|
|
395
|
+
const [cookieVendorId, setCookieVendorId] = React26.useState(() => {
|
|
396
|
+
if (typeof window === "undefined") return null;
|
|
397
|
+
try {
|
|
398
|
+
const match = document.cookie.match(/(?:^|;\s*)infuro_active_vendor_id=(\d+)/);
|
|
399
|
+
if (match && match[1]) return Number(match[1]);
|
|
400
|
+
const stored = localStorage.getItem("infuro_active_vendor_id");
|
|
401
|
+
if (stored) return Number(stored);
|
|
402
|
+
} catch {
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
});
|
|
406
|
+
const [fetchedStores, setFetchedStores] = React26.useState(null);
|
|
407
|
+
const [fetchedRoleName, setFetchedRoleName] = React26.useState(null);
|
|
408
|
+
const [fetchedActiveVendorId, setFetchedActiveVendorId] = React26.useState(null);
|
|
409
|
+
React26.useEffect(() => {
|
|
410
|
+
if (sessionUser?.vendorStores && sessionUser.vendorStores.length > 1 && !cookieVendorId) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
let isMounted = true;
|
|
414
|
+
fetch("/api/admin/vendor/context").then((res) => res.ok ? res.json() : null).then((data) => {
|
|
415
|
+
if (!isMounted || !data) return;
|
|
416
|
+
if (Array.isArray(data.vendorStores)) {
|
|
417
|
+
setFetchedStores(data.vendorStores);
|
|
418
|
+
}
|
|
419
|
+
if (data.vendorRoleName) {
|
|
420
|
+
setFetchedRoleName(data.vendorRoleName);
|
|
421
|
+
}
|
|
422
|
+
if (typeof data.activeVendorId === "number") {
|
|
423
|
+
setFetchedActiveVendorId(data.activeVendorId);
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
427
|
+
window.dispatchEvent(new CustomEvent("infuro_vendor_context_updated", {
|
|
428
|
+
detail: data
|
|
429
|
+
}));
|
|
430
|
+
} catch {
|
|
431
|
+
}
|
|
432
|
+
}).catch(() => {
|
|
433
|
+
});
|
|
434
|
+
return () => {
|
|
435
|
+
isMounted = false;
|
|
436
|
+
};
|
|
437
|
+
}, [
|
|
438
|
+
sessionUser?.email,
|
|
439
|
+
sessionUser?.vendorStores,
|
|
440
|
+
cookieVendorId
|
|
441
|
+
]);
|
|
442
|
+
const stores = React26.useMemo(() => {
|
|
443
|
+
if (sessionUser?.vendorStores && sessionUser.vendorStores.length > 0) {
|
|
444
|
+
return sessionUser.vendorStores;
|
|
445
|
+
}
|
|
446
|
+
return fetchedStores || [];
|
|
447
|
+
}, [
|
|
448
|
+
sessionUser?.vendorStores,
|
|
449
|
+
fetchedStores
|
|
450
|
+
]);
|
|
451
|
+
const effectiveActiveVendorId = cookieVendorId ?? sessionUser?.activeVendorId ?? fetchedActiveVendorId;
|
|
452
|
+
const activeStore = React26.useMemo(() => {
|
|
453
|
+
return stores.find((s) => s.id === effectiveActiveVendorId) || (stores.length > 0 ? stores[0] : null);
|
|
454
|
+
}, [
|
|
455
|
+
stores,
|
|
456
|
+
effectiveActiveVendorId
|
|
457
|
+
]);
|
|
458
|
+
const effectiveRoleName = activeStore?.roleName || sessionUser?.vendorRoleName || fetchedRoleName;
|
|
459
|
+
const roleLabel = ((isVendor || stores.length > 0) && effectiveRoleName ? effectiveRoleName : null) || sessionUser?.groupName?.trim() || (sessionUser?.isRBACAdmin ? "Administrator" : "Admin user");
|
|
395
460
|
const handleLogout = /* @__PURE__ */ __name(() => {
|
|
396
461
|
void adminSignOut();
|
|
397
462
|
}, "handleLogout");
|
|
463
|
+
const handleSwitchStore = /* @__PURE__ */ __name(async (vendorId) => {
|
|
464
|
+
if (vendorId === activeStore?.id || isSwitching) return;
|
|
465
|
+
try {
|
|
466
|
+
setIsSwitching(true);
|
|
467
|
+
document.cookie = `infuro_active_vendor_id=${vendorId}; path=/; max-age=31536000; SameSite=Lax`;
|
|
468
|
+
try {
|
|
469
|
+
localStorage.setItem("infuro_active_vendor_id", String(vendorId));
|
|
470
|
+
} catch {
|
|
471
|
+
}
|
|
472
|
+
setCookieVendorId(vendorId);
|
|
473
|
+
const res = await fetch("/api/admin/vendor/switch", {
|
|
474
|
+
method: "POST",
|
|
475
|
+
headers: {
|
|
476
|
+
"Content-Type": "application/json"
|
|
477
|
+
},
|
|
478
|
+
body: JSON.stringify({
|
|
479
|
+
vendorId
|
|
480
|
+
})
|
|
481
|
+
});
|
|
482
|
+
if (res.ok) {
|
|
483
|
+
const data = await res.json();
|
|
484
|
+
try {
|
|
485
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
486
|
+
window.dispatchEvent(new CustomEvent("infuro_vendor_context_updated", {
|
|
487
|
+
detail: data
|
|
488
|
+
}));
|
|
489
|
+
} catch {
|
|
490
|
+
}
|
|
491
|
+
if (typeof update === "function") {
|
|
492
|
+
try {
|
|
493
|
+
await update({
|
|
494
|
+
activeVendorId: vendorId,
|
|
495
|
+
vendorRole: data.vendorRole,
|
|
496
|
+
vendorRoleId: data.vendorRoleId,
|
|
497
|
+
vendorRoleName: data.vendorRoleName,
|
|
498
|
+
isVendorRoleOwner: data.isVendorRoleOwner,
|
|
499
|
+
vendorEntityPerms: data.vendorEntityPerms,
|
|
500
|
+
vendorStores: data.vendorStores
|
|
501
|
+
});
|
|
502
|
+
} catch {
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
window.location.reload();
|
|
506
|
+
}
|
|
507
|
+
} catch (err) {
|
|
508
|
+
console.error("Failed to switch store:", err);
|
|
509
|
+
} finally {
|
|
510
|
+
setIsSwitching(false);
|
|
511
|
+
}
|
|
512
|
+
}, "handleSwitchStore");
|
|
398
513
|
return /* @__PURE__ */ React.createElement("header", {
|
|
399
514
|
className: "bg-white border-b border-gray-200 px-4 py-2"
|
|
400
515
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
@@ -427,7 +542,46 @@ function AdminHeader() {
|
|
|
427
542
|
className: "text-sm font-semibold text-gray-800"
|
|
428
543
|
}, "Infuro"))), /* @__PURE__ */ React.createElement("div", {
|
|
429
544
|
className: "flex items-center space-x-3"
|
|
430
|
-
}, /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
545
|
+
}, stores.length > 1 && /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
546
|
+
asChild: true
|
|
547
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
548
|
+
variant: "outline",
|
|
549
|
+
size: "sm",
|
|
550
|
+
disabled: isSwitching,
|
|
551
|
+
className: "h-8 px-2.5 flex items-center gap-1.5 border-gray-200 bg-gray-50/80 hover:bg-gray-100 text-gray-800 text-xs font-medium rounded-lg shadow-none transition-colors"
|
|
552
|
+
}, isSwitching ? /* @__PURE__ */ React.createElement(LucideIcons.Loader2, {
|
|
553
|
+
className: "h-3.5 w-3.5 animate-spin text-gray-500 shrink-0"
|
|
554
|
+
}) : /* @__PURE__ */ React.createElement(LucideIcons.Store, {
|
|
555
|
+
className: "h-3.5 w-3.5 text-gray-500 shrink-0"
|
|
556
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
557
|
+
className: "max-w-[130px] sm:max-w-[180px] truncate font-semibold"
|
|
558
|
+
}, activeStore?.name || "Select Store"), activeStore?.roleName && /* @__PURE__ */ React.createElement("span", {
|
|
559
|
+
className: "hidden sm:inline-block px-1.5 py-0.5 text-[10px] font-medium bg-gray-200/80 text-gray-700 rounded"
|
|
560
|
+
}, activeStore.roleName), /* @__PURE__ */ React.createElement(LucideIcons.ChevronDown, {
|
|
561
|
+
className: "h-3 w-3 text-gray-400 shrink-0"
|
|
562
|
+
}))), /* @__PURE__ */ React.createElement(DropdownMenuContent, {
|
|
563
|
+
align: "end",
|
|
564
|
+
className: "w-56 p-1"
|
|
565
|
+
}, /* @__PURE__ */ React.createElement(DropdownMenuLabel, {
|
|
566
|
+
className: "text-[11px] font-semibold text-gray-500 uppercase px-2 py-1"
|
|
567
|
+
}, "Switch Store"), /* @__PURE__ */ React.createElement(DropdownMenuSeparator, {
|
|
568
|
+
className: "my-1"
|
|
569
|
+
}), stores.map((st) => {
|
|
570
|
+
const isSelected = st.id === activeStore?.id;
|
|
571
|
+
return /* @__PURE__ */ React.createElement(DropdownMenuItem, {
|
|
572
|
+
key: st.id,
|
|
573
|
+
onClick: /* @__PURE__ */ __name(() => handleSwitchStore(st.id), "onClick"),
|
|
574
|
+
className: "flex items-center justify-between px-2.5 py-2 cursor-pointer text-xs rounded-md"
|
|
575
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
576
|
+
className: "flex flex-col gap-0.5 truncate pr-2"
|
|
577
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
578
|
+
className: `font-medium ${isSelected ? "text-primary font-semibold" : "text-gray-800"}`
|
|
579
|
+
}, st.name), st.roleName && /* @__PURE__ */ React.createElement("span", {
|
|
580
|
+
className: "text-[10px] text-gray-400"
|
|
581
|
+
}, st.roleName)), isSelected && /* @__PURE__ */ React.createElement(LucideIcons.Check, {
|
|
582
|
+
className: "h-3.5 w-3.5 text-primary shrink-0"
|
|
583
|
+
}));
|
|
584
|
+
}))), /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
431
585
|
asChild: true
|
|
432
586
|
}, /* @__PURE__ */ React.createElement(Button, {
|
|
433
587
|
variant: "ghost",
|
|
@@ -895,7 +1049,7 @@ var init_admin_config_context = __esm({
|
|
|
895
1049
|
var CMS_VERSION;
|
|
896
1050
|
var init_cms_version = __esm({
|
|
897
1051
|
"src/lib/cms-version.ts"() {
|
|
898
|
-
CMS_VERSION = "1.0.
|
|
1052
|
+
CMS_VERSION = "1.0.73" ;
|
|
899
1053
|
}
|
|
900
1054
|
});
|
|
901
1055
|
function useCatalogCategories(enabled = true) {
|
|
@@ -1003,8 +1157,54 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
1003
1157
|
const searchParams = navigation.useSearchParams();
|
|
1004
1158
|
const { data: session } = react.useSession();
|
|
1005
1159
|
const sessionUser = session?.user;
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1160
|
+
const [vendorContext, setVendorContext] = React26.useState(() => {
|
|
1161
|
+
if (typeof window === "undefined") return null;
|
|
1162
|
+
try {
|
|
1163
|
+
const stored = localStorage.getItem("infuro_active_vendor_context");
|
|
1164
|
+
if (stored) return JSON.parse(stored);
|
|
1165
|
+
} catch {
|
|
1166
|
+
}
|
|
1167
|
+
return null;
|
|
1168
|
+
});
|
|
1169
|
+
React26.useEffect(() => {
|
|
1170
|
+
const onContextUpdated = /* @__PURE__ */ __name((e) => {
|
|
1171
|
+
const detail = e.detail;
|
|
1172
|
+
if (detail) setVendorContext(detail);
|
|
1173
|
+
}, "onContextUpdated");
|
|
1174
|
+
window.addEventListener("infuro_vendor_context_updated", onContextUpdated);
|
|
1175
|
+
fetch("/api/admin/vendor/context").then((r) => r.ok ? r.json() : null).then((data) => {
|
|
1176
|
+
if (data) {
|
|
1177
|
+
setVendorContext(data);
|
|
1178
|
+
try {
|
|
1179
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
1180
|
+
} catch {
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}).catch(() => {
|
|
1184
|
+
});
|
|
1185
|
+
return () => {
|
|
1186
|
+
window.removeEventListener("infuro_vendor_context_updated", onContextUpdated);
|
|
1187
|
+
};
|
|
1188
|
+
}, []);
|
|
1189
|
+
const effectiveSessionUser = React26.useMemo(() => {
|
|
1190
|
+
if (!sessionUser) return null;
|
|
1191
|
+
if (!vendorContext) return sessionUser;
|
|
1192
|
+
return {
|
|
1193
|
+
...sessionUser,
|
|
1194
|
+
activeVendorId: vendorContext.activeVendorId ?? sessionUser.activeVendorId,
|
|
1195
|
+
vendorRole: vendorContext.vendorRole ?? sessionUser.vendorRole,
|
|
1196
|
+
vendorRoleId: vendorContext.vendorRoleId ?? sessionUser.vendorRoleId,
|
|
1197
|
+
vendorRoleName: vendorContext.vendorRoleName ?? sessionUser.vendorRoleName,
|
|
1198
|
+
isVendorRoleOwner: vendorContext.isVendorRoleOwner ?? sessionUser.isVendorRoleOwner,
|
|
1199
|
+
vendorEntityPerms: vendorContext.vendorEntityPerms ?? sessionUser.vendorEntityPerms,
|
|
1200
|
+
vendorStores: vendorContext.vendorStores ?? sessionUser.vendorStores
|
|
1201
|
+
};
|
|
1202
|
+
}, [
|
|
1203
|
+
sessionUser,
|
|
1204
|
+
vendorContext
|
|
1205
|
+
]);
|
|
1206
|
+
const showVendorOnboard = canOnboardVendors(effectiveSessionUser);
|
|
1207
|
+
const vendorPortal = isVendorPortalUser(effectiveSessionUser);
|
|
1008
1208
|
const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled, vendorCanCreateCategories, vendorCanCreateCollections, vendorCanCreateBrands } = React26.useContext(exports.AdminConfigContext);
|
|
1009
1209
|
const showStoreNav = storeEnabled || vendorPortal;
|
|
1010
1210
|
const showPlatformNav = !vendorPortal;
|
|
@@ -1031,8 +1231,8 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
1031
1231
|
const headingCls = "text-[11px] font-semibold text-gray-400 uppercase tracking-wider px-2.5 mb-1.5";
|
|
1032
1232
|
const asideCls = isDrawer ? "w-full h-full min-h-0 bg-white flex flex-col overflow-hidden" : "w-52 h-full min-h-0 bg-white border-r border-gray-200 flex-shrink-0 flex flex-col overflow-hidden";
|
|
1033
1233
|
const canReadEntity = /* @__PURE__ */ __name((entity) => {
|
|
1034
|
-
if (!
|
|
1035
|
-
return sessionHasEntityAccessFromExplanation(
|
|
1234
|
+
if (!effectiveSessionUser) return true;
|
|
1235
|
+
return sessionHasEntityAccessFromExplanation(effectiveSessionUser, entity, "read");
|
|
1036
1236
|
}, "canReadEntity");
|
|
1037
1237
|
return /* @__PURE__ */ React.createElement("aside", {
|
|
1038
1238
|
className: asideCls
|
|
@@ -1242,12 +1442,12 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
1242
1442
|
className: `${linkCls} ${isActive("/admin/vendor-profile") ? linkActive : linkInactive}`
|
|
1243
1443
|
}, /* @__PURE__ */ React.createElement(LucideIcons.User, {
|
|
1244
1444
|
className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-profile") ? iconActive : iconInactive}`
|
|
1245
|
-
}), "Profile")), canManageVendorTeam(
|
|
1445
|
+
}), "Profile")), canManageVendorTeam(effectiveSessionUser) && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
|
|
1246
1446
|
href: "/admin/vendor-team",
|
|
1247
1447
|
className: `${linkCls} ${isActive("/admin/vendor-team") ? linkActive : linkInactive}`
|
|
1248
1448
|
}, /* @__PURE__ */ React.createElement(LucideIcons.Users, {
|
|
1249
1449
|
className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-team") ? iconActive : iconInactive}`
|
|
1250
|
-
}), "Team")), canManageVendorRoles(
|
|
1450
|
+
}), "Team")), canManageVendorRoles(effectiveSessionUser) && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2__default.default, {
|
|
1251
1451
|
href: "/admin/vendor-roles",
|
|
1252
1452
|
className: `${linkCls} ${isActive("/admin/vendor-roles") ? linkActive : linkInactive}`
|
|
1253
1453
|
}, /* @__PURE__ */ React.createElement(LucideIcons.Shield, {
|
|
@@ -6438,6 +6638,20 @@ var init_FieldConfiguration = __esm({
|
|
|
6438
6638
|
}
|
|
6439
6639
|
});
|
|
6440
6640
|
|
|
6641
|
+
// src/lib/slug-sanitizer.ts
|
|
6642
|
+
function sanitizeSlugInput(value) {
|
|
6643
|
+
return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-");
|
|
6644
|
+
}
|
|
6645
|
+
function normalizeSlug(value) {
|
|
6646
|
+
return sanitizeSlugInput(value).replace(/^-+|-+$/g, "");
|
|
6647
|
+
}
|
|
6648
|
+
var init_slug_sanitizer = __esm({
|
|
6649
|
+
"src/lib/slug-sanitizer.ts"() {
|
|
6650
|
+
__name(sanitizeSlugInput, "sanitizeSlugInput");
|
|
6651
|
+
__name(normalizeSlug, "normalizeSlug");
|
|
6652
|
+
}
|
|
6653
|
+
});
|
|
6654
|
+
|
|
6441
6655
|
// src/components/Admin/FormBuilder.tsx
|
|
6442
6656
|
var FormBuilder_exports = {};
|
|
6443
6657
|
__export(FormBuilder_exports, {
|
|
@@ -6516,18 +6730,6 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6516
6730
|
loadId,
|
|
6517
6731
|
loadFormData
|
|
6518
6732
|
]);
|
|
6519
|
-
React26.useEffect(() => {
|
|
6520
|
-
if (formData.name && !formData.slug) {
|
|
6521
|
-
const generatedSlug = formData.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
6522
|
-
setFormData((prev) => ({
|
|
6523
|
-
...prev,
|
|
6524
|
-
slug: generatedSlug
|
|
6525
|
-
}));
|
|
6526
|
-
}
|
|
6527
|
-
}, [
|
|
6528
|
-
formData.name,
|
|
6529
|
-
formData.slug
|
|
6530
|
-
]);
|
|
6531
6733
|
const addField = /* @__PURE__ */ __name(() => {
|
|
6532
6734
|
const newField = {
|
|
6533
6735
|
id: `field_${Date.now()}`,
|
|
@@ -6632,6 +6834,7 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6632
6834
|
setErrors([]);
|
|
6633
6835
|
const payload = {
|
|
6634
6836
|
...formData,
|
|
6837
|
+
slug: normalizeSlug(formData.slug),
|
|
6635
6838
|
published: isPublishing ? true : formData.published,
|
|
6636
6839
|
fields: formData.fields.map((field) => {
|
|
6637
6840
|
const numericId = typeof field.id === "number" ? field.id : /^\d+$/.test(String(field.id)) ? parseInt(String(field.id), 10) : void 0;
|
|
@@ -6762,8 +6965,12 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6762
6965
|
value: formData.slug,
|
|
6763
6966
|
onChange: /* @__PURE__ */ __name((e) => setFormData((prev) => ({
|
|
6764
6967
|
...prev,
|
|
6765
|
-
slug: e.target.value
|
|
6968
|
+
slug: sanitizeSlugInput(e.target.value)
|
|
6766
6969
|
})), "onChange"),
|
|
6970
|
+
onBlur: /* @__PURE__ */ __name(() => setFormData((prev) => ({
|
|
6971
|
+
...prev,
|
|
6972
|
+
slug: normalizeSlug(prev.slug)
|
|
6973
|
+
})), "onBlur"),
|
|
6767
6974
|
placeholder: "form-slug"
|
|
6768
6975
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
6769
6976
|
className: "block text-sm font-medium text-gray-700 mb-1"
|
|
@@ -6952,6 +7159,7 @@ var init_FormBuilder = __esm({
|
|
|
6952
7159
|
init_switch();
|
|
6953
7160
|
init_badge();
|
|
6954
7161
|
init_FieldConfiguration();
|
|
7162
|
+
init_slug_sanitizer();
|
|
6955
7163
|
__name(FormBuilder, "FormBuilder");
|
|
6956
7164
|
}
|
|
6957
7165
|
});
|
|
@@ -8001,9 +8209,10 @@ function BlogEditor({ existingBlog, duplicateSource }) {
|
|
|
8001
8209
|
setIsSaving(false);
|
|
8002
8210
|
return;
|
|
8003
8211
|
}
|
|
8212
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
8004
8213
|
const body = {
|
|
8005
8214
|
title,
|
|
8006
|
-
slug,
|
|
8215
|
+
slug: normalizedSlug,
|
|
8007
8216
|
content,
|
|
8008
8217
|
published: isPublishing,
|
|
8009
8218
|
tags,
|
|
@@ -8273,7 +8482,8 @@ function BlogEditor({ existingBlog, duplicateSource }) {
|
|
|
8273
8482
|
type: "text",
|
|
8274
8483
|
placeholder: "blog-post-url",
|
|
8275
8484
|
value: slug,
|
|
8276
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
8485
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
8486
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
8277
8487
|
className: "h-8 text-sm"
|
|
8278
8488
|
}), /* @__PURE__ */ React.createElement("p", {
|
|
8279
8489
|
className: "text-xs text-gray-500 mt-1"
|
|
@@ -8366,6 +8576,7 @@ var init_BlogEditorPage = __esm({
|
|
|
8366
8576
|
init_JoditRichText();
|
|
8367
8577
|
init_CategoryAutocomplete();
|
|
8368
8578
|
init_UserAutocomplete();
|
|
8579
|
+
init_slug_sanitizer();
|
|
8369
8580
|
__name(BlogEditor, "BlogEditor");
|
|
8370
8581
|
}
|
|
8371
8582
|
});
|
|
@@ -24475,7 +24686,8 @@ function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", close
|
|
|
24475
24686
|
size: "icon",
|
|
24476
24687
|
className: "h-8 w-8 border border-gray-600 bg-transparent text-white hover:bg-gray-700",
|
|
24477
24688
|
onClick: item.onClick,
|
|
24478
|
-
title: item.label
|
|
24689
|
+
title: item.label,
|
|
24690
|
+
disabled: item.disabled
|
|
24479
24691
|
}, /* @__PURE__ */ React.createElement(Icon2, {
|
|
24480
24692
|
className: "h-4 w-4"
|
|
24481
24693
|
}), /* @__PURE__ */ React.createElement("span", {
|
|
@@ -24489,7 +24701,8 @@ function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", close
|
|
|
24489
24701
|
key: i,
|
|
24490
24702
|
variant: item.variant ?? "outline",
|
|
24491
24703
|
size: "sm",
|
|
24492
|
-
onClick: item.onClick
|
|
24704
|
+
onClick: item.onClick,
|
|
24705
|
+
disabled: item.disabled
|
|
24493
24706
|
}, /* @__PURE__ */ React.createElement(Icon2, {
|
|
24494
24707
|
className: "h-4 w-4 mr-1"
|
|
24495
24708
|
}), item.label);
|
|
@@ -26950,14 +27163,55 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26950
27163
|
status: "available"
|
|
26951
27164
|
});
|
|
26952
27165
|
if (q.length >= 2) params.set("search", q);
|
|
26953
|
-
const res = await
|
|
27166
|
+
const [res, epRes, evRes] = await Promise.all([
|
|
27167
|
+
fetch(`/api/products?${params}`),
|
|
27168
|
+
fetch("/api/event_products?limit=500").catch(() => null),
|
|
27169
|
+
fetch("/api/events?limit=500").catch(() => null)
|
|
27170
|
+
]);
|
|
26954
27171
|
if (!res.ok) {
|
|
26955
27172
|
setProductHits([]);
|
|
26956
27173
|
return;
|
|
26957
27174
|
}
|
|
26958
27175
|
const body = await res.json();
|
|
26959
27176
|
const hits = Array.isArray(body.data) ? body.data : [];
|
|
26960
|
-
|
|
27177
|
+
const eventMap = /* @__PURE__ */ new Map();
|
|
27178
|
+
if (evRes && evRes.ok) {
|
|
27179
|
+
const evBody = await evRes.json().catch(() => ({}));
|
|
27180
|
+
const evList = Array.isArray(evBody.data) ? evBody.data : [];
|
|
27181
|
+
for (const ev of evList) {
|
|
27182
|
+
if (ev && ev.id) eventMap.set(Number(ev.id), ev);
|
|
27183
|
+
}
|
|
27184
|
+
}
|
|
27185
|
+
const productEventLimits = /* @__PURE__ */ new Map();
|
|
27186
|
+
if (epRes && epRes.ok) {
|
|
27187
|
+
const epBody = await epRes.json().catch(() => ({}));
|
|
27188
|
+
const epList = Array.isArray(epBody.data) ? epBody.data : [];
|
|
27189
|
+
for (const ep of epList) {
|
|
27190
|
+
const ev = eventMap.get(Number(ep.eventId));
|
|
27191
|
+
if (ev) {
|
|
27192
|
+
const maxGroup = typeof ev.maxGroupPurchaseQuantity === "number" && Number.isFinite(ev.maxGroupPurchaseQuantity) && ev.maxGroupPurchaseQuantity > 0 ? Math.floor(ev.maxGroupPurchaseQuantity) : null;
|
|
27193
|
+
const allowsGroup = ev.allowGroupOrders !== false;
|
|
27194
|
+
let cap;
|
|
27195
|
+
if (maxGroup !== null && maxGroup > 1) {
|
|
27196
|
+
cap = maxGroup;
|
|
27197
|
+
} else if (!allowsGroup) {
|
|
27198
|
+
cap = 1;
|
|
27199
|
+
} else if (maxGroup !== null) {
|
|
27200
|
+
cap = maxGroup;
|
|
27201
|
+
} else {
|
|
27202
|
+
cap = 999;
|
|
27203
|
+
}
|
|
27204
|
+
productEventLimits.set(Number(ep.productId), cap);
|
|
27205
|
+
}
|
|
27206
|
+
}
|
|
27207
|
+
}
|
|
27208
|
+
hits.forEach((p) => {
|
|
27209
|
+
const cap = productEventLimits.get(p.id);
|
|
27210
|
+
if (cap !== void 0) {
|
|
27211
|
+
p.maxPurchaseLimit = cap;
|
|
27212
|
+
}
|
|
27213
|
+
productCache.current.set(p.id, p);
|
|
27214
|
+
});
|
|
26961
27215
|
setProductHits(hits);
|
|
26962
27216
|
} catch {
|
|
26963
27217
|
setProductHits([]);
|
|
@@ -27234,6 +27488,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27234
27488
|
sonner.toast.message("Select one or more products in the list first");
|
|
27235
27489
|
return;
|
|
27236
27490
|
}
|
|
27491
|
+
let reachedLimit = false;
|
|
27237
27492
|
setLines((prev) => {
|
|
27238
27493
|
const next = [
|
|
27239
27494
|
...prev
|
|
@@ -27241,29 +27496,47 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27241
27496
|
for (const id of stagedIds) {
|
|
27242
27497
|
const hit = productCache.current.get(id);
|
|
27243
27498
|
if (!hit) continue;
|
|
27499
|
+
const maxAllowed = typeof hit.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27244
27500
|
const idx = next.findIndex((l) => l.productId === id);
|
|
27245
27501
|
if (idx >= 0) {
|
|
27246
27502
|
const row = next[idx];
|
|
27247
|
-
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
|
|
27251
|
-
|
|
27252
|
-
|
|
27253
|
-
|
|
27254
|
-
|
|
27255
|
-
|
|
27256
|
-
|
|
27257
|
-
|
|
27503
|
+
if (row.quantity >= maxAllowed) {
|
|
27504
|
+
reachedLimit = true;
|
|
27505
|
+
} else {
|
|
27506
|
+
next[idx] = {
|
|
27507
|
+
...row,
|
|
27508
|
+
quantity: Math.min(maxAllowed, row.quantity + 1)
|
|
27509
|
+
};
|
|
27510
|
+
}
|
|
27511
|
+
} else {
|
|
27512
|
+
next.push({
|
|
27513
|
+
key: String(id),
|
|
27514
|
+
productId: id,
|
|
27515
|
+
label: hit.name ?? `Product #${id}`,
|
|
27516
|
+
sku: hit.sku,
|
|
27517
|
+
quantity: 1
|
|
27518
|
+
});
|
|
27519
|
+
}
|
|
27258
27520
|
}
|
|
27259
27521
|
return next;
|
|
27260
27522
|
});
|
|
27261
27523
|
setStagedIds(/* @__PURE__ */ new Set());
|
|
27262
|
-
|
|
27524
|
+
if (reachedLimit) {
|
|
27525
|
+
sonner.toast.error("One or more items reached their maximum purchase limit");
|
|
27526
|
+
} else {
|
|
27527
|
+
sonner.toast.success("Added to cart");
|
|
27528
|
+
}
|
|
27263
27529
|
}
|
|
27264
27530
|
__name(addStagedToCart, "addStagedToCart");
|
|
27265
27531
|
function updateQty(key, quantity) {
|
|
27266
|
-
const
|
|
27532
|
+
const line = lines.find((l) => l.key === key);
|
|
27533
|
+
const hit = line ? productCache.current.get(line.productId) : null;
|
|
27534
|
+
const maxAllowed = typeof hit?.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27535
|
+
const parsed = Math.max(1, Math.floor(quantity) || 1);
|
|
27536
|
+
const q = Math.min(maxAllowed, parsed);
|
|
27537
|
+
if (parsed > maxAllowed) {
|
|
27538
|
+
sonner.toast.error(`Maximum purchase limit for "${line?.label ?? "this product"}" is ${maxAllowed}`);
|
|
27539
|
+
}
|
|
27267
27540
|
setLines((prev) => prev.map((l) => l.key === key ? {
|
|
27268
27541
|
...l,
|
|
27269
27542
|
quantity: q
|
|
@@ -27313,6 +27586,13 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27313
27586
|
sonner.toast.error("Add at least one product to the cart");
|
|
27314
27587
|
return;
|
|
27315
27588
|
}
|
|
27589
|
+
for (const line of lines) {
|
|
27590
|
+
const hit = productCache.current.get(line.productId);
|
|
27591
|
+
if (hit?.maxPurchaseLimit && line.quantity > hit.maxPurchaseLimit) {
|
|
27592
|
+
sonner.toast.error(`Quantity for "${line.label}" cannot exceed maximum allowed limit of ${hit.maxPurchaseLimit}`);
|
|
27593
|
+
return;
|
|
27594
|
+
}
|
|
27595
|
+
}
|
|
27316
27596
|
const unknown = preview?.lines.filter((l) => !l.found) ?? [];
|
|
27317
27597
|
if (unknown.length > 0) {
|
|
27318
27598
|
sonner.toast.error(`One or more items could not be validated: ${unknown.map((u) => u.productName).join(", ")}`);
|
|
@@ -27975,6 +28255,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27975
28255
|
}, /* @__PURE__ */ React.createElement(Input, {
|
|
27976
28256
|
type: "number",
|
|
27977
28257
|
min: 1,
|
|
28258
|
+
max: productCache.current.get(line.productId)?.maxPurchaseLimit ?? void 0,
|
|
27978
28259
|
className: "h-8 w-14 ml-auto text-right",
|
|
27979
28260
|
value: line.quantity,
|
|
27980
28261
|
onChange: /* @__PURE__ */ __name((e) => updateQty(line.key, Number(e.target.value)), "onChange"),
|
|
@@ -30575,9 +30856,10 @@ function SaveButton({ pageId, pageData, existingSeoId, onSeoIdChange, onSaved, c
|
|
|
30575
30856
|
}
|
|
30576
30857
|
}
|
|
30577
30858
|
}
|
|
30859
|
+
const normalizedSlug = normalizeSlug(pageData.slug);
|
|
30578
30860
|
const payload = {
|
|
30579
30861
|
title: pageData.title,
|
|
30580
|
-
slug:
|
|
30862
|
+
slug: normalizedSlug,
|
|
30581
30863
|
content,
|
|
30582
30864
|
published: pageData.published
|
|
30583
30865
|
};
|
|
@@ -30817,7 +31099,8 @@ function PageBuilderPage({ pageId }) {
|
|
|
30817
31099
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
30818
31100
|
}, "Slug *"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
|
|
30819
31101
|
value: slug,
|
|
30820
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
31102
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31103
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
30821
31104
|
placeholder: "page-url-slug",
|
|
30822
31105
|
className: "h-8 text-sm"
|
|
30823
31106
|
})))), /* @__PURE__ */ React26__namespace.default.createElement(RightSidebar, {
|
|
@@ -30854,6 +31137,7 @@ var init_PageBuilderPage = __esm({
|
|
|
30854
31137
|
init_admin_config_context();
|
|
30855
31138
|
init_registry();
|
|
30856
31139
|
init_ImageOrUrlField();
|
|
31140
|
+
init_slug_sanitizer();
|
|
30857
31141
|
__name(createSelectable, "createSelectable");
|
|
30858
31142
|
__name(buildEditorResolver, "buildEditorResolver");
|
|
30859
31143
|
__name(getIcon, "getIcon");
|
|
@@ -31087,7 +31371,8 @@ function BrandEditPage({ brandId }) {
|
|
|
31087
31371
|
]);
|
|
31088
31372
|
return;
|
|
31089
31373
|
}
|
|
31090
|
-
|
|
31374
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
31375
|
+
if (!normalizedSlug) {
|
|
31091
31376
|
setErrors([
|
|
31092
31377
|
"Slug is required"
|
|
31093
31378
|
]);
|
|
@@ -31095,10 +31380,10 @@ function BrandEditPage({ brandId }) {
|
|
|
31095
31380
|
}
|
|
31096
31381
|
setSaving(true);
|
|
31097
31382
|
try {
|
|
31098
|
-
const savedSeoId = await saveSeo(seo,
|
|
31383
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
31099
31384
|
const payload = {
|
|
31100
31385
|
name: name.trim(),
|
|
31101
|
-
slug:
|
|
31386
|
+
slug: normalizedSlug,
|
|
31102
31387
|
description: description || null,
|
|
31103
31388
|
logo: logo || null,
|
|
31104
31389
|
active,
|
|
@@ -31188,7 +31473,9 @@ function BrandEditPage({ brandId }) {
|
|
|
31188
31473
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
31189
31474
|
type: "text",
|
|
31190
31475
|
value: slug,
|
|
31191
|
-
|
|
31476
|
+
placeholder: "brand-slug",
|
|
31477
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31478
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
31192
31479
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm",
|
|
31193
31480
|
required: true
|
|
31194
31481
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -31248,6 +31535,7 @@ var init_BrandEditPage = __esm({
|
|
|
31248
31535
|
init_DetailPageHeader();
|
|
31249
31536
|
init_vendor_scope();
|
|
31250
31537
|
init_ImageOrUrlField();
|
|
31538
|
+
init_slug_sanitizer();
|
|
31251
31539
|
isCreate = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
31252
31540
|
__name(BrandEditPage, "BrandEditPage");
|
|
31253
31541
|
}
|
|
@@ -32712,11 +33000,21 @@ function ProductEditPage({ productId }) {
|
|
|
32712
33000
|
const pcData = await pcRes.json();
|
|
32713
33001
|
const pcs = Array.isArray(pcData.data) ? pcData.data : [];
|
|
32714
33002
|
if (pcs.length > 0) {
|
|
32715
|
-
|
|
32716
|
-
|
|
32717
|
-
|
|
32718
|
-
|
|
32719
|
-
|
|
33003
|
+
const validTaxPcs = pcs.filter((p) => p.taxId != null && Number(p.taxId) > 0);
|
|
33004
|
+
if (validTaxPcs.length > 0) {
|
|
33005
|
+
setTaxRows(validTaxPcs.map((p) => ({
|
|
33006
|
+
taxId: p.taxId,
|
|
33007
|
+
rate: p.rate != null && p.rate !== "" ? String(p.rate) : ""
|
|
33008
|
+
})));
|
|
33009
|
+
} else if (!cancelled) {
|
|
33010
|
+
setTaxRows([
|
|
33011
|
+
{
|
|
33012
|
+
taxId: "",
|
|
33013
|
+
rate: ""
|
|
33014
|
+
}
|
|
33015
|
+
]);
|
|
33016
|
+
}
|
|
33017
|
+
const firstRefund = pcs.find((p) => p.refundPolicyId != null)?.refundPolicyId;
|
|
32720
33018
|
setRefundPolicyId(firstRefund != null ? Number(firstRefund) : null);
|
|
32721
33019
|
} else if (!cancelled) {
|
|
32722
33020
|
setTaxRows([
|
|
@@ -32725,6 +33023,7 @@ function ProductEditPage({ productId }) {
|
|
|
32725
33023
|
rate: ""
|
|
32726
33024
|
}
|
|
32727
33025
|
]);
|
|
33026
|
+
setRefundPolicyId(null);
|
|
32728
33027
|
}
|
|
32729
33028
|
}
|
|
32730
33029
|
const paRes = await fetch(`/api/product_attributes?productId=${sourceProductId}&limit=100`);
|
|
@@ -33101,14 +33400,7 @@ function ProductEditPage({ productId }) {
|
|
|
33101
33400
|
if (a == null || b == null) return true;
|
|
33102
33401
|
return Math.abs(a - b) > 1e-6;
|
|
33103
33402
|
}, "ratesDiffer");
|
|
33104
|
-
const
|
|
33105
|
-
for (const row of taxRows) {
|
|
33106
|
-
if (row.taxId === "") continue;
|
|
33107
|
-
wantedConfig.set(row.taxId, {
|
|
33108
|
-
rate: parseTaxRate(row.rate),
|
|
33109
|
-
refundPolicyId
|
|
33110
|
-
});
|
|
33111
|
-
}
|
|
33403
|
+
const validTaxRows = taxRows.filter((row) => row.taxId !== "");
|
|
33112
33404
|
console.log("[product_config rows to save]:", taxRows, "refundPolicyId:", refundPolicyId);
|
|
33113
33405
|
const pcListRes = await fetch(`/api/product_config?productId=${savedId}&limit=200`);
|
|
33114
33406
|
const pcListData = pcListRes.ok ? await pcListRes.json() : {
|
|
@@ -33116,17 +33408,60 @@ function ProductEditPage({ productId }) {
|
|
|
33116
33408
|
};
|
|
33117
33409
|
console.log("[product existing pc rows]:", pcListData);
|
|
33118
33410
|
const existingPc = Array.isArray(pcListData.data) ? pcListData.data : [];
|
|
33119
|
-
|
|
33120
|
-
|
|
33121
|
-
|
|
33122
|
-
|
|
33123
|
-
|
|
33411
|
+
if (validTaxRows.length > 0) {
|
|
33412
|
+
const wantedTaxIds = new Set(validTaxRows.map((r) => Number(r.taxId)));
|
|
33413
|
+
for (const ep of existingPc) {
|
|
33414
|
+
if (ep.taxId == null || !wantedTaxIds.has(Number(ep.taxId))) {
|
|
33415
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33416
|
+
method: "DELETE"
|
|
33417
|
+
});
|
|
33418
|
+
}
|
|
33124
33419
|
}
|
|
33125
|
-
|
|
33126
|
-
|
|
33127
|
-
|
|
33128
|
-
|
|
33129
|
-
|
|
33420
|
+
for (const row of validTaxRows) {
|
|
33421
|
+
const taxId = Number(row.taxId);
|
|
33422
|
+
const rate = parseTaxRate(row.rate);
|
|
33423
|
+
const ep = existingPc.find((e) => e.taxId != null && Number(e.taxId) === taxId);
|
|
33424
|
+
if (!ep) {
|
|
33425
|
+
await fetch("/api/product_config", {
|
|
33426
|
+
method: "POST",
|
|
33427
|
+
headers: {
|
|
33428
|
+
"Content-Type": "application/json"
|
|
33429
|
+
},
|
|
33430
|
+
body: JSON.stringify({
|
|
33431
|
+
productId: Number(savedId),
|
|
33432
|
+
taxId,
|
|
33433
|
+
rate,
|
|
33434
|
+
refundPolicyId
|
|
33435
|
+
})
|
|
33436
|
+
});
|
|
33437
|
+
} else {
|
|
33438
|
+
const existingRate = ep.rate == null || String(ep.rate).trim() === "" ? null : Number(ep.rate);
|
|
33439
|
+
const er = Number.isFinite(existingRate) ? existingRate : null;
|
|
33440
|
+
const policyChanged = ep.refundPolicyId !== refundPolicyId;
|
|
33441
|
+
if (ratesDiffer(er, rate) || policyChanged) {
|
|
33442
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33443
|
+
method: "PUT",
|
|
33444
|
+
headers: {
|
|
33445
|
+
"Content-Type": "application/json"
|
|
33446
|
+
},
|
|
33447
|
+
body: JSON.stringify({
|
|
33448
|
+
rate,
|
|
33449
|
+
refundPolicyId
|
|
33450
|
+
})
|
|
33451
|
+
});
|
|
33452
|
+
}
|
|
33453
|
+
}
|
|
33454
|
+
}
|
|
33455
|
+
} else if (refundPolicyId != null) {
|
|
33456
|
+
const nullTaxRow = existingPc.find((e) => e.taxId == null);
|
|
33457
|
+
for (const ep of existingPc) {
|
|
33458
|
+
if (ep.id !== nullTaxRow?.id) {
|
|
33459
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33460
|
+
method: "DELETE"
|
|
33461
|
+
});
|
|
33462
|
+
}
|
|
33463
|
+
}
|
|
33464
|
+
if (!nullTaxRow) {
|
|
33130
33465
|
await fetch("/api/product_config", {
|
|
33131
33466
|
method: "POST",
|
|
33132
33467
|
headers: {
|
|
@@ -33134,27 +33469,27 @@ function ProductEditPage({ productId }) {
|
|
|
33134
33469
|
},
|
|
33135
33470
|
body: JSON.stringify({
|
|
33136
33471
|
productId: Number(savedId),
|
|
33137
|
-
taxId,
|
|
33138
|
-
rate:
|
|
33139
|
-
refundPolicyId
|
|
33472
|
+
taxId: null,
|
|
33473
|
+
rate: null,
|
|
33474
|
+
refundPolicyId
|
|
33140
33475
|
})
|
|
33141
33476
|
});
|
|
33142
|
-
} else {
|
|
33143
|
-
|
|
33144
|
-
|
|
33145
|
-
|
|
33146
|
-
|
|
33147
|
-
|
|
33148
|
-
|
|
33149
|
-
|
|
33150
|
-
|
|
33151
|
-
|
|
33152
|
-
|
|
33153
|
-
|
|
33154
|
-
|
|
33155
|
-
|
|
33156
|
-
|
|
33157
|
-
}
|
|
33477
|
+
} else if (nullTaxRow.refundPolicyId !== refundPolicyId) {
|
|
33478
|
+
await fetch(`/api/product_config/${nullTaxRow.id}`, {
|
|
33479
|
+
method: "PUT",
|
|
33480
|
+
headers: {
|
|
33481
|
+
"Content-Type": "application/json"
|
|
33482
|
+
},
|
|
33483
|
+
body: JSON.stringify({
|
|
33484
|
+
refundPolicyId
|
|
33485
|
+
})
|
|
33486
|
+
});
|
|
33487
|
+
}
|
|
33488
|
+
} else {
|
|
33489
|
+
for (const ep of existingPc) {
|
|
33490
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33491
|
+
method: "DELETE"
|
|
33492
|
+
});
|
|
33158
33493
|
}
|
|
33159
33494
|
}
|
|
33160
33495
|
if (hasVariants) {
|
|
@@ -34070,7 +34405,8 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34070
34405
|
]);
|
|
34071
34406
|
return;
|
|
34072
34407
|
}
|
|
34073
|
-
|
|
34408
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
34409
|
+
if (!normalizedSlug) {
|
|
34074
34410
|
setErrors([
|
|
34075
34411
|
"Slug is required"
|
|
34076
34412
|
]);
|
|
@@ -34078,10 +34414,10 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34078
34414
|
}
|
|
34079
34415
|
setSaving(true);
|
|
34080
34416
|
try {
|
|
34081
|
-
const savedSeoId = await saveSeo(seo,
|
|
34417
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
34082
34418
|
const payload = {
|
|
34083
34419
|
name: name.trim(),
|
|
34084
|
-
slug:
|
|
34420
|
+
slug: normalizedSlug,
|
|
34085
34421
|
hsn: hsn.trim() || null,
|
|
34086
34422
|
categoryId: categoryId || null,
|
|
34087
34423
|
brandId: brandId || null,
|
|
@@ -34250,7 +34586,9 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34250
34586
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
34251
34587
|
type: "text",
|
|
34252
34588
|
value: slug,
|
|
34253
|
-
|
|
34589
|
+
placeholder: "collection-slug",
|
|
34590
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
34591
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
34254
34592
|
className: inputCls4,
|
|
34255
34593
|
required: true
|
|
34256
34594
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -34486,6 +34824,7 @@ var init_CollectionEditPage = __esm({
|
|
|
34486
34824
|
init_admin_config_context();
|
|
34487
34825
|
init_category_related_product_labels();
|
|
34488
34826
|
init_ImageOrUrlField();
|
|
34827
|
+
init_slug_sanitizer();
|
|
34489
34828
|
isCreate3 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
34490
34829
|
emptySlide = /* @__PURE__ */ __name(() => ({
|
|
34491
34830
|
url: "",
|
|
@@ -35665,7 +36004,9 @@ var init_event_entity_types = __esm({
|
|
|
35665
36004
|
// src/admin/pages/EventEditPage.tsx
|
|
35666
36005
|
var EventEditPage_exports = {};
|
|
35667
36006
|
__export(EventEditPage_exports, {
|
|
35668
|
-
default: () => EventEditPage
|
|
36007
|
+
default: () => EventEditPage,
|
|
36008
|
+
normalizeSlug: () => normalizeSlug2,
|
|
36009
|
+
sanitizeSlugInput: () => sanitizeSlugInput2
|
|
35669
36010
|
});
|
|
35670
36011
|
function RequiredLabel({ children }) {
|
|
35671
36012
|
return /* @__PURE__ */ React.createElement("label", {
|
|
@@ -35674,6 +36015,12 @@ function RequiredLabel({ children }) {
|
|
|
35674
36015
|
className: "text-red-600"
|
|
35675
36016
|
}, "*"));
|
|
35676
36017
|
}
|
|
36018
|
+
function sanitizeSlugInput2(value) {
|
|
36019
|
+
return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-");
|
|
36020
|
+
}
|
|
36021
|
+
function normalizeSlug2(value) {
|
|
36022
|
+
return sanitizeSlugInput2(value).replace(/^-+|-+$/g, "");
|
|
36023
|
+
}
|
|
35677
36024
|
function toIsoOrNull(value, timezone) {
|
|
35678
36025
|
const trimmed = value.trim();
|
|
35679
36026
|
if (!trimmed) return null;
|
|
@@ -35764,7 +36111,7 @@ function EventEditPage({ eventId }) {
|
|
|
35764
36111
|
const [supportContact, setSupportContact] = React26.useState("");
|
|
35765
36112
|
const [allowGroupOrders, setAllowGroupOrders] = React26.useState(false);
|
|
35766
36113
|
const [sendIndividualTicketPDFToAttendees, setSendIndividualTicketPDFToAttendees] = React26.useState(false);
|
|
35767
|
-
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = React26.useState("");
|
|
36114
|
+
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = React26.useState("1");
|
|
35768
36115
|
const [sponsors, setSponsors] = React26.useState([]);
|
|
35769
36116
|
const [agenda, setAgenda] = React26.useState([]);
|
|
35770
36117
|
const [workshops, setWorkshops] = React26.useState([]);
|
|
@@ -35890,9 +36237,10 @@ function EventEditPage({ eventId }) {
|
|
|
35890
36237
|
}
|
|
35891
36238
|
setOfficialWebsiteUrl(data.officialWebsiteUrl ?? "");
|
|
35892
36239
|
setSupportContact(data.supportContact ?? "");
|
|
35893
|
-
|
|
36240
|
+
const loadedAllowGroup = data.allowGroupOrders ?? false;
|
|
36241
|
+
setAllowGroupOrders(loadedAllowGroup);
|
|
35894
36242
|
setSendIndividualTicketPDFToAttendees(data.sendIndividualTicketPDFToAttendees ?? false);
|
|
35895
|
-
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : "");
|
|
36243
|
+
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : loadedAllowGroup ? "10" : "1");
|
|
35896
36244
|
setSponsors(parseNamedListFromApi(data.sponsors, "sponsor"));
|
|
35897
36245
|
setAgenda(parseNamedListFromApi(data.agenda, "agenda"));
|
|
35898
36246
|
setWorkshops(parseNamedListFromApi(data.workshops, "workshop"));
|
|
@@ -35938,8 +36286,13 @@ function EventEditPage({ eventId }) {
|
|
|
35938
36286
|
]);
|
|
35939
36287
|
const buildPayload = /* @__PURE__ */ __name(() => {
|
|
35940
36288
|
const nextErrors = [];
|
|
36289
|
+
const normalizedSlug = normalizeSlug2(slug);
|
|
35941
36290
|
if (!name.trim()) nextErrors.push("Name is required");
|
|
35942
|
-
if (!
|
|
36291
|
+
if (!normalizedSlug) {
|
|
36292
|
+
nextErrors.push("Slug is required");
|
|
36293
|
+
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalizedSlug)) {
|
|
36294
|
+
nextErrors.push("Slug must contain only lowercase letters, numbers, and hyphens without leading or trailing hyphens or slashes");
|
|
36295
|
+
}
|
|
35943
36296
|
if (!startDate.trim()) nextErrors.push("Event Start Date & Time is required");
|
|
35944
36297
|
if (!endDate.trim()) nextErrors.push("Event End Date & Time is required");
|
|
35945
36298
|
if (startDate.trim() && !timezone.trim()) {
|
|
@@ -35965,6 +36318,20 @@ function EventEditPage({ eventId }) {
|
|
|
35965
36318
|
nextErrors.push("Event End Date & Time must be after Event Start Date & Time");
|
|
35966
36319
|
}
|
|
35967
36320
|
}
|
|
36321
|
+
if (registrationOpensAt.trim() && registrationClosesAt.trim()) {
|
|
36322
|
+
const regOpen = new Date(toIsoOrNull(registrationOpensAt, timezone) ?? "");
|
|
36323
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36324
|
+
if (!Number.isNaN(regOpen.getTime()) && !Number.isNaN(regClose.getTime()) && regClose < regOpen) {
|
|
36325
|
+
nextErrors.push("Registration Closes Date & Time must be after Registration Opens Date & Time");
|
|
36326
|
+
}
|
|
36327
|
+
}
|
|
36328
|
+
if (registrationClosesAt.trim() && endDate.trim()) {
|
|
36329
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36330
|
+
const end = new Date(toIsoOrNull(endDate, timezone) ?? "");
|
|
36331
|
+
if (!Number.isNaN(regClose.getTime()) && !Number.isNaN(end.getTime()) && regClose > end) {
|
|
36332
|
+
nextErrors.push("Registration cannot close after Event End Date & Time");
|
|
36333
|
+
}
|
|
36334
|
+
}
|
|
35968
36335
|
if (additionalVenueDetails.length > ADDITIONAL_VENUE_MAX_CHARS) {
|
|
35969
36336
|
nextErrors.push(`Additional Venue Details must be ${ADDITIONAL_VENUE_MAX_CHARS} characters or fewer`);
|
|
35970
36337
|
}
|
|
@@ -35974,7 +36341,7 @@ function EventEditPage({ eventId }) {
|
|
|
35974
36341
|
}
|
|
35975
36342
|
const payload = {
|
|
35976
36343
|
name: name.trim(),
|
|
35977
|
-
slug:
|
|
36344
|
+
slug: normalizedSlug,
|
|
35978
36345
|
description: description.trim() || null,
|
|
35979
36346
|
isActive: create && vendorPortal && approvalOn ? false : isActive,
|
|
35980
36347
|
comingSoon,
|
|
@@ -36002,7 +36369,7 @@ function EventEditPage({ eventId }) {
|
|
|
36002
36369
|
supportContact: supportContact.trim() || null,
|
|
36003
36370
|
allowGroupOrders,
|
|
36004
36371
|
sendIndividualTicketPDFToAttendees,
|
|
36005
|
-
maxGroupPurchaseQuantity: maxGroupPurchaseQuantity
|
|
36372
|
+
maxGroupPurchaseQuantity: allowGroupOrders ? Number(maxGroupPurchaseQuantity) > 0 ? Number(maxGroupPurchaseQuantity) : 10 : 1,
|
|
36006
36373
|
sponsors: namedListToPayload(sponsors, {
|
|
36007
36374
|
legacySponsorKeys: true
|
|
36008
36375
|
}),
|
|
@@ -36270,9 +36637,16 @@ function EventEditPage({ eventId }) {
|
|
|
36270
36637
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36271
36638
|
className: labelCls6
|
|
36272
36639
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
36640
|
+
id: "event-slug",
|
|
36273
36641
|
type: "text",
|
|
36274
36642
|
value: slug,
|
|
36275
|
-
|
|
36643
|
+
placeholder: "event-slug",
|
|
36644
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36645
|
+
setSlug(sanitizeSlugInput2(e.target.value));
|
|
36646
|
+
}, "onChange"),
|
|
36647
|
+
onBlur: /* @__PURE__ */ __name(() => {
|
|
36648
|
+
setSlug((prev) => normalizeSlug2(prev));
|
|
36649
|
+
}, "onBlur"),
|
|
36276
36650
|
className: inputCls6
|
|
36277
36651
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36278
36652
|
className: labelCls6
|
|
@@ -36532,7 +36906,16 @@ function EventEditPage({ eventId }) {
|
|
|
36532
36906
|
}, "Max group purchase quantity"), /* @__PURE__ */ React.createElement("input", {
|
|
36533
36907
|
type: "number",
|
|
36534
36908
|
value: maxGroupPurchaseQuantity,
|
|
36535
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36909
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36910
|
+
const val = e.target.value;
|
|
36911
|
+
setMaxGroupPurchaseQuantity(val);
|
|
36912
|
+
const num = Number(val);
|
|
36913
|
+
if (Number.isFinite(num) && num > 1) {
|
|
36914
|
+
setAllowGroupOrders(true);
|
|
36915
|
+
} else if (Number.isFinite(num) && num <= 1) {
|
|
36916
|
+
setAllowGroupOrders(false);
|
|
36917
|
+
}
|
|
36918
|
+
}, "onChange"),
|
|
36536
36919
|
className: inputCls6,
|
|
36537
36920
|
min: 1
|
|
36538
36921
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
@@ -36542,7 +36925,18 @@ function EventEditPage({ eventId }) {
|
|
|
36542
36925
|
}, /* @__PURE__ */ React.createElement("input", {
|
|
36543
36926
|
type: "checkbox",
|
|
36544
36927
|
checked: allowGroupOrders,
|
|
36545
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36928
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36929
|
+
const checked = e.target.checked;
|
|
36930
|
+
setAllowGroupOrders(checked);
|
|
36931
|
+
if (!checked) {
|
|
36932
|
+
setMaxGroupPurchaseQuantity("1");
|
|
36933
|
+
} else {
|
|
36934
|
+
const current = Number(maxGroupPurchaseQuantity);
|
|
36935
|
+
if (!Number.isFinite(current) || current <= 1) {
|
|
36936
|
+
setMaxGroupPurchaseQuantity("10");
|
|
36937
|
+
}
|
|
36938
|
+
}
|
|
36939
|
+
}, "onChange"),
|
|
36546
36940
|
className: "h-4 w-4 rounded border-gray-300"
|
|
36547
36941
|
}), /* @__PURE__ */ React.createElement("span", {
|
|
36548
36942
|
className: "text-sm text-gray-900"
|
|
@@ -36616,6 +37010,8 @@ var init_EventEditPage = __esm({
|
|
|
36616
37010
|
labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
|
|
36617
37011
|
inputCls6 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
36618
37012
|
__name(RequiredLabel, "RequiredLabel");
|
|
37013
|
+
__name(sanitizeSlugInput2, "sanitizeSlugInput");
|
|
37014
|
+
__name(normalizeSlug2, "normalizeSlug");
|
|
36619
37015
|
ENTITY_TYPE_OPTIONS = [
|
|
36620
37016
|
...EVENT_ENTITY_TYPE_OPTIONS
|
|
36621
37017
|
];
|
|
@@ -36994,7 +37390,7 @@ function ComboEditPage({ comboId }) {
|
|
|
36994
37390
|
const resolvedEventId = trimmedEventId && /^\d+$/.test(trimmedEventId) ? Number(trimmedEventId) : null;
|
|
36995
37391
|
const payload = {
|
|
36996
37392
|
name: trimmedName,
|
|
36997
|
-
slug: slug.trim()
|
|
37393
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
36998
37394
|
desc: desc || null,
|
|
36999
37395
|
eventId: resolvedEventId,
|
|
37000
37396
|
price,
|
|
@@ -37089,8 +37485,9 @@ function ComboEditPage({ comboId }) {
|
|
|
37089
37485
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
37090
37486
|
type: "text",
|
|
37091
37487
|
value: slug,
|
|
37092
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37093
|
-
|
|
37488
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
37489
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
37490
|
+
placeholder: "combo-slug",
|
|
37094
37491
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
37095
37492
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
37096
37493
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
@@ -37256,6 +37653,7 @@ var init_ComboEditPage = __esm({
|
|
|
37256
37653
|
init_DetailPageHeader();
|
|
37257
37654
|
init_inventory_validation();
|
|
37258
37655
|
init_admin_config_context();
|
|
37656
|
+
init_slug_sanitizer();
|
|
37259
37657
|
isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
37260
37658
|
__name(formatDateTimeLocal, "formatDateTimeLocal");
|
|
37261
37659
|
__name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
|
|
@@ -37319,6 +37717,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37319
37717
|
const create = isCreate6(vendorId);
|
|
37320
37718
|
const [loading, setLoading] = React26.useState(!create);
|
|
37321
37719
|
const [saving, setSaving] = React26.useState(false);
|
|
37720
|
+
const createInFlightRef = React26.useRef(false);
|
|
37322
37721
|
const [errors, setErrors] = React26.useState([]);
|
|
37323
37722
|
const [name, setName] = React26.useState("");
|
|
37324
37723
|
const [legalName, setLegalName] = React26.useState("");
|
|
@@ -37486,7 +37885,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37486
37885
|
const vendorPayload = /* @__PURE__ */ __name(() => ({
|
|
37487
37886
|
name: name.trim(),
|
|
37488
37887
|
legalName: legalName.trim() || null,
|
|
37489
|
-
slug: slug.trim()
|
|
37888
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37490
37889
|
businessType: businessType || null,
|
|
37491
37890
|
description: description.trim() || null,
|
|
37492
37891
|
website: website.trim() || null,
|
|
@@ -37677,7 +38076,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37677
38076
|
router.push(listReturnUrl);
|
|
37678
38077
|
}, "closeInviteDialog");
|
|
37679
38078
|
const handleCreate = /* @__PURE__ */ __name(async () => {
|
|
37680
|
-
|
|
38079
|
+
if (createInFlightRef.current) return;
|
|
37681
38080
|
setErrors([]);
|
|
37682
38081
|
const createMissing = [];
|
|
37683
38082
|
if (!name.trim()) createMissing.push("Store name is required");
|
|
@@ -37685,14 +38084,12 @@ function VendorEditPage({ vendorId }) {
|
|
|
37685
38084
|
if (!ownerEmail.trim()) createMissing.push("Owner email is required");
|
|
37686
38085
|
if (createMissing.length) {
|
|
37687
38086
|
setErrors(createMissing);
|
|
37688
|
-
setSaving(false);
|
|
37689
38087
|
return;
|
|
37690
38088
|
}
|
|
37691
38089
|
if (!termsAccepted) {
|
|
37692
38090
|
setErrors([
|
|
37693
38091
|
"You must confirm that the vendor has accepted the terms and conditions"
|
|
37694
38092
|
]);
|
|
37695
|
-
setSaving(false);
|
|
37696
38093
|
return;
|
|
37697
38094
|
}
|
|
37698
38095
|
const formattedOwnerPhone = formatPhoneWithCountryCode(ownerPhoneCode, ownerPhoneNum);
|
|
@@ -37703,7 +38100,6 @@ function VendorEditPage({ vendorId }) {
|
|
|
37703
38100
|
setErrors([
|
|
37704
38101
|
taxError
|
|
37705
38102
|
]);
|
|
37706
|
-
setSaving(false);
|
|
37707
38103
|
return;
|
|
37708
38104
|
}
|
|
37709
38105
|
const personErr = validatePersonKyc({
|
|
@@ -37716,25 +38112,22 @@ function VendorEditPage({ vendorId }) {
|
|
|
37716
38112
|
setErrors([
|
|
37717
38113
|
personErr
|
|
37718
38114
|
]);
|
|
37719
|
-
setSaving(false);
|
|
37720
38115
|
return;
|
|
37721
38116
|
}
|
|
37722
38117
|
if (!ownerAddressLine1.trim()) {
|
|
37723
38118
|
setErrors([
|
|
37724
38119
|
"Owner address line 1 is required"
|
|
37725
38120
|
]);
|
|
37726
|
-
setSaving(false);
|
|
37727
38121
|
return;
|
|
37728
38122
|
}
|
|
37729
|
-
|
|
37730
|
-
|
|
38123
|
+
createInFlightRef.current = true;
|
|
38124
|
+
setSaving(true);
|
|
37731
38125
|
try {
|
|
37732
38126
|
const res = await fetch("/api/admin/vendors/onboard", {
|
|
37733
38127
|
method: "POST",
|
|
37734
38128
|
headers: {
|
|
37735
38129
|
"Content-Type": "application/json"
|
|
37736
38130
|
},
|
|
37737
|
-
signal: abortController.signal,
|
|
37738
38131
|
body: JSON.stringify({
|
|
37739
38132
|
activation: "invite",
|
|
37740
38133
|
sendOwnerEmail: false,
|
|
@@ -37755,7 +38148,6 @@ function VendorEditPage({ vendorId }) {
|
|
|
37755
38148
|
}
|
|
37756
38149
|
})
|
|
37757
38150
|
});
|
|
37758
|
-
clearTimeout(timeoutId);
|
|
37759
38151
|
const data = await res.json().catch(() => ({}));
|
|
37760
38152
|
if (!res.ok) {
|
|
37761
38153
|
setErrors([
|
|
@@ -37781,17 +38173,11 @@ function VendorEditPage({ vendorId }) {
|
|
|
37781
38173
|
inviteLink
|
|
37782
38174
|
});
|
|
37783
38175
|
} catch (err) {
|
|
37784
|
-
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
]);
|
|
37788
|
-
} else {
|
|
37789
|
-
setErrors([
|
|
37790
|
-
err instanceof Error && err.message || "Request failed"
|
|
37791
|
-
]);
|
|
37792
|
-
}
|
|
38176
|
+
setErrors([
|
|
38177
|
+
err instanceof Error && err.message || "Request failed"
|
|
38178
|
+
]);
|
|
37793
38179
|
} finally {
|
|
37794
|
-
|
|
38180
|
+
createInFlightRef.current = false;
|
|
37795
38181
|
setSaving(false);
|
|
37796
38182
|
}
|
|
37797
38183
|
}, "handleCreate");
|
|
@@ -37841,7 +38227,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37841
38227
|
signal: abortController.signal,
|
|
37842
38228
|
body: JSON.stringify({
|
|
37843
38229
|
...vendorPayload(),
|
|
37844
|
-
slug: slug.trim(),
|
|
38230
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37845
38231
|
metadata: (() => {
|
|
37846
38232
|
const next = {
|
|
37847
38233
|
...metadata ?? {}
|
|
@@ -37919,13 +38305,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
37919
38305
|
{
|
|
37920
38306
|
label: saving ? "Creating\u2026" : "Create vendor",
|
|
37921
38307
|
icon: LucideIcons.Save,
|
|
37922
|
-
onClick: handleCreate
|
|
38308
|
+
onClick: handleCreate,
|
|
38309
|
+
disabled: saving
|
|
37923
38310
|
}
|
|
37924
38311
|
] : [
|
|
37925
38312
|
{
|
|
37926
38313
|
label: saving ? "Saving\u2026" : "Save",
|
|
37927
38314
|
icon: LucideIcons.Save,
|
|
37928
|
-
onClick: handleSave
|
|
38315
|
+
onClick: handleSave,
|
|
38316
|
+
disabled: saving
|
|
37929
38317
|
},
|
|
37930
38318
|
{
|
|
37931
38319
|
label: active ? "Deactivate" : "Activate",
|
|
@@ -37962,8 +38350,9 @@ function VendorEditPage({ vendorId }) {
|
|
|
37962
38350
|
}, "Slug ", create ? "(optional)" : "*"), /* @__PURE__ */ React26__namespace.default.createElement(Input, {
|
|
37963
38351
|
id: "vendorSlug",
|
|
37964
38352
|
value: slug,
|
|
37965
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37966
|
-
|
|
38353
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
38354
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
38355
|
+
placeholder: "vendor-slug",
|
|
37967
38356
|
className: `mt-1 ${fieldClass}`
|
|
37968
38357
|
})), /* @__PURE__ */ React26__namespace.default.createElement("div", null, /* @__PURE__ */ React26__namespace.default.createElement(FieldLabel, {
|
|
37969
38358
|
htmlFor: "businessType"
|
|
@@ -38304,6 +38693,7 @@ var init_VendorEditPage = __esm({
|
|
|
38304
38693
|
init_checkbox();
|
|
38305
38694
|
init_dialog();
|
|
38306
38695
|
init_vendor_profile();
|
|
38696
|
+
init_slug_sanitizer();
|
|
38307
38697
|
init_vendor_list_config();
|
|
38308
38698
|
init_vendor_access_denied();
|
|
38309
38699
|
init_vendor_access_denied();
|