@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.js
CHANGED
|
@@ -3,14 +3,14 @@ import { useSession, signOut, signIn } from 'next-auth/react';
|
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import * as React26 from 'react';
|
|
6
|
-
import React26__default, { useState, useMemo,
|
|
6
|
+
import React26__default, { useState, useMemo, useEffect, useContext, useRef, useCallback, Suspense, createElement, createContext } from 'react';
|
|
7
7
|
var React = React26__default;
|
|
8
8
|
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
10
10
|
import { cva } from 'class-variance-authority';
|
|
11
11
|
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
12
12
|
import * as LucideIcons from 'lucide-react';
|
|
13
|
-
import { ChevronDown, User, Settings, LogOut, LayoutDashboard,
|
|
13
|
+
import { Loader2, Store, ChevronDown, Check, User, Settings, LogOut, LayoutDashboard, FolderTree, Layers, Building2, CalendarDays, ShoppingBag, Package, Receipt, BadgePercent, ShoppingCart, CreditCard, Users, Inbox, File, LinkIcon, ClipboardList, MessageSquare, Image as Image$1, Shield, FileText, Puzzle, X, ShieldAlert, Plus, MoreVertical, Upload, Download, Edit, Copy, RefreshCw, Trash2, Mail, Save, Search, AlertCircle, MapPin, BarChart3, TrendingUp, UserCheck, Activity, Globe, Eye, MousePointer, ArrowLeftRight, RotateCcw, KeyRound, CalendarClock, CheckCircle2, XCircle, CheckSquare, Square, XSquare, Rss, ArrowLeft, PlayCircle, UserPlus, Pencil, ShieldCheck, Smartphone, Send, FolderPlus, LayoutGrid, List, Move, Archive, Edit2, ExternalLink, Power, Star, ChevronUp, Zap, Filter, ImageIcon, GripVertical, ChevronRight, ArrowRight, ArrowUpRight, IndianRupee, Clock, Play, MessageCircle, Bot, FileUp, Tag, Box, SlidersHorizontal, Calculator, Link2 as Link2$1, Unlink, Gift, MoreHorizontal, EyeOff, Phone, QrCode, Car, Settings2, DollarSign, Hash, Circle, ChevronLeft, Bell, Share2, HardDrive, Folder, Film } from 'lucide-react';
|
|
14
14
|
import Image from 'next/image';
|
|
15
15
|
import Link2 from 'next/link';
|
|
16
16
|
import { usePathname, useSearchParams, useRouter } from 'next/navigation';
|
|
@@ -347,9 +347,8 @@ var init_vendor_scope = __esm({
|
|
|
347
347
|
}
|
|
348
348
|
});
|
|
349
349
|
function AdminHeader() {
|
|
350
|
-
const { data: session } = useSession();
|
|
350
|
+
const { data: session, update } = useSession();
|
|
351
351
|
const sessionUser = session?.user;
|
|
352
|
-
const roleLabel = sessionUser?.groupName?.trim() || (sessionUser?.isRBACAdmin ? "Administrator" : "Admin user");
|
|
353
352
|
const isVendor = isVendorPortalUser(sessionUser);
|
|
354
353
|
const isMobile = useIsMobile();
|
|
355
354
|
const configuredLogo = process.env.NEXT_PUBLIC_ADMIN_LOGO_URL || DEFAULT_ADMIN_LOGO;
|
|
@@ -358,9 +357,125 @@ function AdminHeader() {
|
|
|
358
357
|
const isDataLogo = useMemo(() => logoSrc.startsWith("data:"), [
|
|
359
358
|
logoSrc
|
|
360
359
|
]);
|
|
360
|
+
const [isSwitching, setIsSwitching] = useState(false);
|
|
361
|
+
const [cookieVendorId, setCookieVendorId] = useState(() => {
|
|
362
|
+
if (typeof window === "undefined") return null;
|
|
363
|
+
try {
|
|
364
|
+
const match = document.cookie.match(/(?:^|;\s*)infuro_active_vendor_id=(\d+)/);
|
|
365
|
+
if (match && match[1]) return Number(match[1]);
|
|
366
|
+
const stored = localStorage.getItem("infuro_active_vendor_id");
|
|
367
|
+
if (stored) return Number(stored);
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
});
|
|
372
|
+
const [fetchedStores, setFetchedStores] = useState(null);
|
|
373
|
+
const [fetchedRoleName, setFetchedRoleName] = useState(null);
|
|
374
|
+
const [fetchedActiveVendorId, setFetchedActiveVendorId] = useState(null);
|
|
375
|
+
useEffect(() => {
|
|
376
|
+
if (sessionUser?.vendorStores && sessionUser.vendorStores.length > 1 && !cookieVendorId) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
let isMounted = true;
|
|
380
|
+
fetch("/api/admin/vendor/context").then((res) => res.ok ? res.json() : null).then((data) => {
|
|
381
|
+
if (!isMounted || !data) return;
|
|
382
|
+
if (Array.isArray(data.vendorStores)) {
|
|
383
|
+
setFetchedStores(data.vendorStores);
|
|
384
|
+
}
|
|
385
|
+
if (data.vendorRoleName) {
|
|
386
|
+
setFetchedRoleName(data.vendorRoleName);
|
|
387
|
+
}
|
|
388
|
+
if (typeof data.activeVendorId === "number") {
|
|
389
|
+
setFetchedActiveVendorId(data.activeVendorId);
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
393
|
+
window.dispatchEvent(new CustomEvent("infuro_vendor_context_updated", {
|
|
394
|
+
detail: data
|
|
395
|
+
}));
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
}).catch(() => {
|
|
399
|
+
});
|
|
400
|
+
return () => {
|
|
401
|
+
isMounted = false;
|
|
402
|
+
};
|
|
403
|
+
}, [
|
|
404
|
+
sessionUser?.email,
|
|
405
|
+
sessionUser?.vendorStores,
|
|
406
|
+
cookieVendorId
|
|
407
|
+
]);
|
|
408
|
+
const stores = useMemo(() => {
|
|
409
|
+
if (sessionUser?.vendorStores && sessionUser.vendorStores.length > 0) {
|
|
410
|
+
return sessionUser.vendorStores;
|
|
411
|
+
}
|
|
412
|
+
return fetchedStores || [];
|
|
413
|
+
}, [
|
|
414
|
+
sessionUser?.vendorStores,
|
|
415
|
+
fetchedStores
|
|
416
|
+
]);
|
|
417
|
+
const effectiveActiveVendorId = cookieVendorId ?? sessionUser?.activeVendorId ?? fetchedActiveVendorId;
|
|
418
|
+
const activeStore = useMemo(() => {
|
|
419
|
+
return stores.find((s) => s.id === effectiveActiveVendorId) || (stores.length > 0 ? stores[0] : null);
|
|
420
|
+
}, [
|
|
421
|
+
stores,
|
|
422
|
+
effectiveActiveVendorId
|
|
423
|
+
]);
|
|
424
|
+
const effectiveRoleName = activeStore?.roleName || sessionUser?.vendorRoleName || fetchedRoleName;
|
|
425
|
+
const roleLabel = ((isVendor || stores.length > 0) && effectiveRoleName ? effectiveRoleName : null) || sessionUser?.groupName?.trim() || (sessionUser?.isRBACAdmin ? "Administrator" : "Admin user");
|
|
361
426
|
const handleLogout = /* @__PURE__ */ __name(() => {
|
|
362
427
|
void adminSignOut();
|
|
363
428
|
}, "handleLogout");
|
|
429
|
+
const handleSwitchStore = /* @__PURE__ */ __name(async (vendorId) => {
|
|
430
|
+
if (vendorId === activeStore?.id || isSwitching) return;
|
|
431
|
+
try {
|
|
432
|
+
setIsSwitching(true);
|
|
433
|
+
document.cookie = `infuro_active_vendor_id=${vendorId}; path=/; max-age=31536000; SameSite=Lax`;
|
|
434
|
+
try {
|
|
435
|
+
localStorage.setItem("infuro_active_vendor_id", String(vendorId));
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
setCookieVendorId(vendorId);
|
|
439
|
+
const res = await fetch("/api/admin/vendor/switch", {
|
|
440
|
+
method: "POST",
|
|
441
|
+
headers: {
|
|
442
|
+
"Content-Type": "application/json"
|
|
443
|
+
},
|
|
444
|
+
body: JSON.stringify({
|
|
445
|
+
vendorId
|
|
446
|
+
})
|
|
447
|
+
});
|
|
448
|
+
if (res.ok) {
|
|
449
|
+
const data = await res.json();
|
|
450
|
+
try {
|
|
451
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
452
|
+
window.dispatchEvent(new CustomEvent("infuro_vendor_context_updated", {
|
|
453
|
+
detail: data
|
|
454
|
+
}));
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
if (typeof update === "function") {
|
|
458
|
+
try {
|
|
459
|
+
await update({
|
|
460
|
+
activeVendorId: vendorId,
|
|
461
|
+
vendorRole: data.vendorRole,
|
|
462
|
+
vendorRoleId: data.vendorRoleId,
|
|
463
|
+
vendorRoleName: data.vendorRoleName,
|
|
464
|
+
isVendorRoleOwner: data.isVendorRoleOwner,
|
|
465
|
+
vendorEntityPerms: data.vendorEntityPerms,
|
|
466
|
+
vendorStores: data.vendorStores
|
|
467
|
+
});
|
|
468
|
+
} catch {
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
window.location.reload();
|
|
472
|
+
}
|
|
473
|
+
} catch (err) {
|
|
474
|
+
console.error("Failed to switch store:", err);
|
|
475
|
+
} finally {
|
|
476
|
+
setIsSwitching(false);
|
|
477
|
+
}
|
|
478
|
+
}, "handleSwitchStore");
|
|
364
479
|
return /* @__PURE__ */ React.createElement("header", {
|
|
365
480
|
className: "bg-white border-b border-gray-200 px-4 py-2"
|
|
366
481
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
@@ -393,7 +508,46 @@ function AdminHeader() {
|
|
|
393
508
|
className: "text-sm font-semibold text-gray-800"
|
|
394
509
|
}, "Infuro"))), /* @__PURE__ */ React.createElement("div", {
|
|
395
510
|
className: "flex items-center space-x-3"
|
|
396
|
-
}, /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
511
|
+
}, stores.length > 1 && /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
512
|
+
asChild: true
|
|
513
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
514
|
+
variant: "outline",
|
|
515
|
+
size: "sm",
|
|
516
|
+
disabled: isSwitching,
|
|
517
|
+
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"
|
|
518
|
+
}, isSwitching ? /* @__PURE__ */ React.createElement(Loader2, {
|
|
519
|
+
className: "h-3.5 w-3.5 animate-spin text-gray-500 shrink-0"
|
|
520
|
+
}) : /* @__PURE__ */ React.createElement(Store, {
|
|
521
|
+
className: "h-3.5 w-3.5 text-gray-500 shrink-0"
|
|
522
|
+
}), /* @__PURE__ */ React.createElement("span", {
|
|
523
|
+
className: "max-w-[130px] sm:max-w-[180px] truncate font-semibold"
|
|
524
|
+
}, activeStore?.name || "Select Store"), activeStore?.roleName && /* @__PURE__ */ React.createElement("span", {
|
|
525
|
+
className: "hidden sm:inline-block px-1.5 py-0.5 text-[10px] font-medium bg-gray-200/80 text-gray-700 rounded"
|
|
526
|
+
}, activeStore.roleName), /* @__PURE__ */ React.createElement(ChevronDown, {
|
|
527
|
+
className: "h-3 w-3 text-gray-400 shrink-0"
|
|
528
|
+
}))), /* @__PURE__ */ React.createElement(DropdownMenuContent, {
|
|
529
|
+
align: "end",
|
|
530
|
+
className: "w-56 p-1"
|
|
531
|
+
}, /* @__PURE__ */ React.createElement(DropdownMenuLabel, {
|
|
532
|
+
className: "text-[11px] font-semibold text-gray-500 uppercase px-2 py-1"
|
|
533
|
+
}, "Switch Store"), /* @__PURE__ */ React.createElement(DropdownMenuSeparator, {
|
|
534
|
+
className: "my-1"
|
|
535
|
+
}), stores.map((st) => {
|
|
536
|
+
const isSelected = st.id === activeStore?.id;
|
|
537
|
+
return /* @__PURE__ */ React.createElement(DropdownMenuItem, {
|
|
538
|
+
key: st.id,
|
|
539
|
+
onClick: /* @__PURE__ */ __name(() => handleSwitchStore(st.id), "onClick"),
|
|
540
|
+
className: "flex items-center justify-between px-2.5 py-2 cursor-pointer text-xs rounded-md"
|
|
541
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
542
|
+
className: "flex flex-col gap-0.5 truncate pr-2"
|
|
543
|
+
}, /* @__PURE__ */ React.createElement("span", {
|
|
544
|
+
className: `font-medium ${isSelected ? "text-primary font-semibold" : "text-gray-800"}`
|
|
545
|
+
}, st.name), st.roleName && /* @__PURE__ */ React.createElement("span", {
|
|
546
|
+
className: "text-[10px] text-gray-400"
|
|
547
|
+
}, st.roleName)), isSelected && /* @__PURE__ */ React.createElement(Check, {
|
|
548
|
+
className: "h-3.5 w-3.5 text-primary shrink-0"
|
|
549
|
+
}));
|
|
550
|
+
}))), /* @__PURE__ */ React.createElement(DropdownMenu, null, /* @__PURE__ */ React.createElement(DropdownMenuTrigger, {
|
|
397
551
|
asChild: true
|
|
398
552
|
}, /* @__PURE__ */ React.createElement(Button, {
|
|
399
553
|
variant: "ghost",
|
|
@@ -861,7 +1015,7 @@ var init_admin_config_context = __esm({
|
|
|
861
1015
|
var CMS_VERSION;
|
|
862
1016
|
var init_cms_version = __esm({
|
|
863
1017
|
"src/lib/cms-version.ts"() {
|
|
864
|
-
CMS_VERSION = "1.0.
|
|
1018
|
+
CMS_VERSION = "1.0.73" ;
|
|
865
1019
|
}
|
|
866
1020
|
});
|
|
867
1021
|
function useCatalogCategories(enabled = true) {
|
|
@@ -969,8 +1123,54 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
969
1123
|
const searchParams = useSearchParams();
|
|
970
1124
|
const { data: session } = useSession();
|
|
971
1125
|
const sessionUser = session?.user;
|
|
972
|
-
const
|
|
973
|
-
|
|
1126
|
+
const [vendorContext, setVendorContext] = useState(() => {
|
|
1127
|
+
if (typeof window === "undefined") return null;
|
|
1128
|
+
try {
|
|
1129
|
+
const stored = localStorage.getItem("infuro_active_vendor_context");
|
|
1130
|
+
if (stored) return JSON.parse(stored);
|
|
1131
|
+
} catch {
|
|
1132
|
+
}
|
|
1133
|
+
return null;
|
|
1134
|
+
});
|
|
1135
|
+
useEffect(() => {
|
|
1136
|
+
const onContextUpdated = /* @__PURE__ */ __name((e) => {
|
|
1137
|
+
const detail = e.detail;
|
|
1138
|
+
if (detail) setVendorContext(detail);
|
|
1139
|
+
}, "onContextUpdated");
|
|
1140
|
+
window.addEventListener("infuro_vendor_context_updated", onContextUpdated);
|
|
1141
|
+
fetch("/api/admin/vendor/context").then((r) => r.ok ? r.json() : null).then((data) => {
|
|
1142
|
+
if (data) {
|
|
1143
|
+
setVendorContext(data);
|
|
1144
|
+
try {
|
|
1145
|
+
localStorage.setItem("infuro_active_vendor_context", JSON.stringify(data));
|
|
1146
|
+
} catch {
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}).catch(() => {
|
|
1150
|
+
});
|
|
1151
|
+
return () => {
|
|
1152
|
+
window.removeEventListener("infuro_vendor_context_updated", onContextUpdated);
|
|
1153
|
+
};
|
|
1154
|
+
}, []);
|
|
1155
|
+
const effectiveSessionUser = useMemo(() => {
|
|
1156
|
+
if (!sessionUser) return null;
|
|
1157
|
+
if (!vendorContext) return sessionUser;
|
|
1158
|
+
return {
|
|
1159
|
+
...sessionUser,
|
|
1160
|
+
activeVendorId: vendorContext.activeVendorId ?? sessionUser.activeVendorId,
|
|
1161
|
+
vendorRole: vendorContext.vendorRole ?? sessionUser.vendorRole,
|
|
1162
|
+
vendorRoleId: vendorContext.vendorRoleId ?? sessionUser.vendorRoleId,
|
|
1163
|
+
vendorRoleName: vendorContext.vendorRoleName ?? sessionUser.vendorRoleName,
|
|
1164
|
+
isVendorRoleOwner: vendorContext.isVendorRoleOwner ?? sessionUser.isVendorRoleOwner,
|
|
1165
|
+
vendorEntityPerms: vendorContext.vendorEntityPerms ?? sessionUser.vendorEntityPerms,
|
|
1166
|
+
vendorStores: vendorContext.vendorStores ?? sessionUser.vendorStores
|
|
1167
|
+
};
|
|
1168
|
+
}, [
|
|
1169
|
+
sessionUser,
|
|
1170
|
+
vendorContext
|
|
1171
|
+
]);
|
|
1172
|
+
const showVendorOnboard = canOnboardVendors(effectiveSessionUser);
|
|
1173
|
+
const vendorPortal = isVendorPortalUser(effectiveSessionUser);
|
|
974
1174
|
const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled, vendorCanCreateCategories, vendorCanCreateCollections, vendorCanCreateBrands } = useContext(AdminConfigContext);
|
|
975
1175
|
const showStoreNav = storeEnabled || vendorPortal;
|
|
976
1176
|
const showPlatformNav = !vendorPortal;
|
|
@@ -997,8 +1197,8 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
997
1197
|
const headingCls = "text-[11px] font-semibold text-gray-400 uppercase tracking-wider px-2.5 mb-1.5";
|
|
998
1198
|
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";
|
|
999
1199
|
const canReadEntity = /* @__PURE__ */ __name((entity) => {
|
|
1000
|
-
if (!
|
|
1001
|
-
return sessionHasEntityAccessFromExplanation(
|
|
1200
|
+
if (!effectiveSessionUser) return true;
|
|
1201
|
+
return sessionHasEntityAccessFromExplanation(effectiveSessionUser, entity, "read");
|
|
1002
1202
|
}, "canReadEntity");
|
|
1003
1203
|
return /* @__PURE__ */ React.createElement("aside", {
|
|
1004
1204
|
className: asideCls
|
|
@@ -1208,12 +1408,12 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
1208
1408
|
className: `${linkCls} ${isActive("/admin/vendor-profile") ? linkActive : linkInactive}`
|
|
1209
1409
|
}, /* @__PURE__ */ React.createElement(User, {
|
|
1210
1410
|
className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-profile") ? iconActive : iconInactive}`
|
|
1211
|
-
}), "Profile")), canManageVendorTeam(
|
|
1411
|
+
}), "Profile")), canManageVendorTeam(effectiveSessionUser) && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
1212
1412
|
href: "/admin/vendor-team",
|
|
1213
1413
|
className: `${linkCls} ${isActive("/admin/vendor-team") ? linkActive : linkInactive}`
|
|
1214
1414
|
}, /* @__PURE__ */ React.createElement(Users, {
|
|
1215
1415
|
className: `h-4 w-4 mr-2 ${isActive("/admin/vendor-team") ? iconActive : iconInactive}`
|
|
1216
|
-
}), "Team")), canManageVendorRoles(
|
|
1416
|
+
}), "Team")), canManageVendorRoles(effectiveSessionUser) && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
1217
1417
|
href: "/admin/vendor-roles",
|
|
1218
1418
|
className: `${linkCls} ${isActive("/admin/vendor-roles") ? linkActive : linkInactive}`
|
|
1219
1419
|
}, /* @__PURE__ */ React.createElement(Shield, {
|
|
@@ -6404,6 +6604,20 @@ var init_FieldConfiguration = __esm({
|
|
|
6404
6604
|
}
|
|
6405
6605
|
});
|
|
6406
6606
|
|
|
6607
|
+
// src/lib/slug-sanitizer.ts
|
|
6608
|
+
function sanitizeSlugInput(value) {
|
|
6609
|
+
return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-");
|
|
6610
|
+
}
|
|
6611
|
+
function normalizeSlug(value) {
|
|
6612
|
+
return sanitizeSlugInput(value).replace(/^-+|-+$/g, "");
|
|
6613
|
+
}
|
|
6614
|
+
var init_slug_sanitizer = __esm({
|
|
6615
|
+
"src/lib/slug-sanitizer.ts"() {
|
|
6616
|
+
__name(sanitizeSlugInput, "sanitizeSlugInput");
|
|
6617
|
+
__name(normalizeSlug, "normalizeSlug");
|
|
6618
|
+
}
|
|
6619
|
+
});
|
|
6620
|
+
|
|
6407
6621
|
// src/components/Admin/FormBuilder.tsx
|
|
6408
6622
|
var FormBuilder_exports = {};
|
|
6409
6623
|
__export(FormBuilder_exports, {
|
|
@@ -6482,18 +6696,6 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6482
6696
|
loadId,
|
|
6483
6697
|
loadFormData
|
|
6484
6698
|
]);
|
|
6485
|
-
useEffect(() => {
|
|
6486
|
-
if (formData.name && !formData.slug) {
|
|
6487
|
-
const generatedSlug = formData.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
6488
|
-
setFormData((prev) => ({
|
|
6489
|
-
...prev,
|
|
6490
|
-
slug: generatedSlug
|
|
6491
|
-
}));
|
|
6492
|
-
}
|
|
6493
|
-
}, [
|
|
6494
|
-
formData.name,
|
|
6495
|
-
formData.slug
|
|
6496
|
-
]);
|
|
6497
6699
|
const addField = /* @__PURE__ */ __name(() => {
|
|
6498
6700
|
const newField = {
|
|
6499
6701
|
id: `field_${Date.now()}`,
|
|
@@ -6598,6 +6800,7 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6598
6800
|
setErrors([]);
|
|
6599
6801
|
const payload = {
|
|
6600
6802
|
...formData,
|
|
6803
|
+
slug: normalizeSlug(formData.slug),
|
|
6601
6804
|
published: isPublishing ? true : formData.published,
|
|
6602
6805
|
fields: formData.fields.map((field) => {
|
|
6603
6806
|
const numericId = typeof field.id === "number" ? field.id : /^\d+$/.test(String(field.id)) ? parseInt(String(field.id), 10) : void 0;
|
|
@@ -6728,8 +6931,12 @@ function FormBuilder({ formId, duplicateFromId }) {
|
|
|
6728
6931
|
value: formData.slug,
|
|
6729
6932
|
onChange: /* @__PURE__ */ __name((e) => setFormData((prev) => ({
|
|
6730
6933
|
...prev,
|
|
6731
|
-
slug: e.target.value
|
|
6934
|
+
slug: sanitizeSlugInput(e.target.value)
|
|
6732
6935
|
})), "onChange"),
|
|
6936
|
+
onBlur: /* @__PURE__ */ __name(() => setFormData((prev) => ({
|
|
6937
|
+
...prev,
|
|
6938
|
+
slug: normalizeSlug(prev.slug)
|
|
6939
|
+
})), "onBlur"),
|
|
6733
6940
|
placeholder: "form-slug"
|
|
6734
6941
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
6735
6942
|
className: "block text-sm font-medium text-gray-700 mb-1"
|
|
@@ -6918,6 +7125,7 @@ var init_FormBuilder = __esm({
|
|
|
6918
7125
|
init_switch();
|
|
6919
7126
|
init_badge();
|
|
6920
7127
|
init_FieldConfiguration();
|
|
7128
|
+
init_slug_sanitizer();
|
|
6921
7129
|
__name(FormBuilder, "FormBuilder");
|
|
6922
7130
|
}
|
|
6923
7131
|
});
|
|
@@ -7967,9 +8175,10 @@ function BlogEditor({ existingBlog, duplicateSource }) {
|
|
|
7967
8175
|
setIsSaving(false);
|
|
7968
8176
|
return;
|
|
7969
8177
|
}
|
|
8178
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
7970
8179
|
const body = {
|
|
7971
8180
|
title,
|
|
7972
|
-
slug,
|
|
8181
|
+
slug: normalizedSlug,
|
|
7973
8182
|
content,
|
|
7974
8183
|
published: isPublishing,
|
|
7975
8184
|
tags,
|
|
@@ -8239,7 +8448,8 @@ function BlogEditor({ existingBlog, duplicateSource }) {
|
|
|
8239
8448
|
type: "text",
|
|
8240
8449
|
placeholder: "blog-post-url",
|
|
8241
8450
|
value: slug,
|
|
8242
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
8451
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
8452
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
8243
8453
|
className: "h-8 text-sm"
|
|
8244
8454
|
}), /* @__PURE__ */ React.createElement("p", {
|
|
8245
8455
|
className: "text-xs text-gray-500 mt-1"
|
|
@@ -8332,6 +8542,7 @@ var init_BlogEditorPage = __esm({
|
|
|
8332
8542
|
init_JoditRichText();
|
|
8333
8543
|
init_CategoryAutocomplete();
|
|
8334
8544
|
init_UserAutocomplete();
|
|
8545
|
+
init_slug_sanitizer();
|
|
8335
8546
|
__name(BlogEditor, "BlogEditor");
|
|
8336
8547
|
}
|
|
8337
8548
|
});
|
|
@@ -24441,7 +24652,8 @@ function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", close
|
|
|
24441
24652
|
size: "icon",
|
|
24442
24653
|
className: "h-8 w-8 border border-gray-600 bg-transparent text-white hover:bg-gray-700",
|
|
24443
24654
|
onClick: item.onClick,
|
|
24444
|
-
title: item.label
|
|
24655
|
+
title: item.label,
|
|
24656
|
+
disabled: item.disabled
|
|
24445
24657
|
}, /* @__PURE__ */ React.createElement(Icon2, {
|
|
24446
24658
|
className: "h-4 w-4"
|
|
24447
24659
|
}), /* @__PURE__ */ React.createElement("span", {
|
|
@@ -24455,7 +24667,8 @@ function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", close
|
|
|
24455
24667
|
key: i,
|
|
24456
24668
|
variant: item.variant ?? "outline",
|
|
24457
24669
|
size: "sm",
|
|
24458
|
-
onClick: item.onClick
|
|
24670
|
+
onClick: item.onClick,
|
|
24671
|
+
disabled: item.disabled
|
|
24459
24672
|
}, /* @__PURE__ */ React.createElement(Icon2, {
|
|
24460
24673
|
className: "h-4 w-4 mr-1"
|
|
24461
24674
|
}), item.label);
|
|
@@ -26916,14 +27129,55 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26916
27129
|
status: "available"
|
|
26917
27130
|
});
|
|
26918
27131
|
if (q.length >= 2) params.set("search", q);
|
|
26919
|
-
const res = await
|
|
27132
|
+
const [res, epRes, evRes] = await Promise.all([
|
|
27133
|
+
fetch(`/api/products?${params}`),
|
|
27134
|
+
fetch("/api/event_products?limit=500").catch(() => null),
|
|
27135
|
+
fetch("/api/events?limit=500").catch(() => null)
|
|
27136
|
+
]);
|
|
26920
27137
|
if (!res.ok) {
|
|
26921
27138
|
setProductHits([]);
|
|
26922
27139
|
return;
|
|
26923
27140
|
}
|
|
26924
27141
|
const body = await res.json();
|
|
26925
27142
|
const hits = Array.isArray(body.data) ? body.data : [];
|
|
26926
|
-
|
|
27143
|
+
const eventMap = /* @__PURE__ */ new Map();
|
|
27144
|
+
if (evRes && evRes.ok) {
|
|
27145
|
+
const evBody = await evRes.json().catch(() => ({}));
|
|
27146
|
+
const evList = Array.isArray(evBody.data) ? evBody.data : [];
|
|
27147
|
+
for (const ev of evList) {
|
|
27148
|
+
if (ev && ev.id) eventMap.set(Number(ev.id), ev);
|
|
27149
|
+
}
|
|
27150
|
+
}
|
|
27151
|
+
const productEventLimits = /* @__PURE__ */ new Map();
|
|
27152
|
+
if (epRes && epRes.ok) {
|
|
27153
|
+
const epBody = await epRes.json().catch(() => ({}));
|
|
27154
|
+
const epList = Array.isArray(epBody.data) ? epBody.data : [];
|
|
27155
|
+
for (const ep of epList) {
|
|
27156
|
+
const ev = eventMap.get(Number(ep.eventId));
|
|
27157
|
+
if (ev) {
|
|
27158
|
+
const maxGroup = typeof ev.maxGroupPurchaseQuantity === "number" && Number.isFinite(ev.maxGroupPurchaseQuantity) && ev.maxGroupPurchaseQuantity > 0 ? Math.floor(ev.maxGroupPurchaseQuantity) : null;
|
|
27159
|
+
const allowsGroup = ev.allowGroupOrders !== false;
|
|
27160
|
+
let cap;
|
|
27161
|
+
if (maxGroup !== null && maxGroup > 1) {
|
|
27162
|
+
cap = maxGroup;
|
|
27163
|
+
} else if (!allowsGroup) {
|
|
27164
|
+
cap = 1;
|
|
27165
|
+
} else if (maxGroup !== null) {
|
|
27166
|
+
cap = maxGroup;
|
|
27167
|
+
} else {
|
|
27168
|
+
cap = 999;
|
|
27169
|
+
}
|
|
27170
|
+
productEventLimits.set(Number(ep.productId), cap);
|
|
27171
|
+
}
|
|
27172
|
+
}
|
|
27173
|
+
}
|
|
27174
|
+
hits.forEach((p) => {
|
|
27175
|
+
const cap = productEventLimits.get(p.id);
|
|
27176
|
+
if (cap !== void 0) {
|
|
27177
|
+
p.maxPurchaseLimit = cap;
|
|
27178
|
+
}
|
|
27179
|
+
productCache.current.set(p.id, p);
|
|
27180
|
+
});
|
|
26927
27181
|
setProductHits(hits);
|
|
26928
27182
|
} catch {
|
|
26929
27183
|
setProductHits([]);
|
|
@@ -27200,6 +27454,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27200
27454
|
toast.message("Select one or more products in the list first");
|
|
27201
27455
|
return;
|
|
27202
27456
|
}
|
|
27457
|
+
let reachedLimit = false;
|
|
27203
27458
|
setLines((prev) => {
|
|
27204
27459
|
const next = [
|
|
27205
27460
|
...prev
|
|
@@ -27207,29 +27462,47 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27207
27462
|
for (const id of stagedIds) {
|
|
27208
27463
|
const hit = productCache.current.get(id);
|
|
27209
27464
|
if (!hit) continue;
|
|
27465
|
+
const maxAllowed = typeof hit.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27210
27466
|
const idx = next.findIndex((l) => l.productId === id);
|
|
27211
27467
|
if (idx >= 0) {
|
|
27212
27468
|
const row = next[idx];
|
|
27213
|
-
|
|
27214
|
-
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
|
|
27222
|
-
|
|
27223
|
-
|
|
27469
|
+
if (row.quantity >= maxAllowed) {
|
|
27470
|
+
reachedLimit = true;
|
|
27471
|
+
} else {
|
|
27472
|
+
next[idx] = {
|
|
27473
|
+
...row,
|
|
27474
|
+
quantity: Math.min(maxAllowed, row.quantity + 1)
|
|
27475
|
+
};
|
|
27476
|
+
}
|
|
27477
|
+
} else {
|
|
27478
|
+
next.push({
|
|
27479
|
+
key: String(id),
|
|
27480
|
+
productId: id,
|
|
27481
|
+
label: hit.name ?? `Product #${id}`,
|
|
27482
|
+
sku: hit.sku,
|
|
27483
|
+
quantity: 1
|
|
27484
|
+
});
|
|
27485
|
+
}
|
|
27224
27486
|
}
|
|
27225
27487
|
return next;
|
|
27226
27488
|
});
|
|
27227
27489
|
setStagedIds(/* @__PURE__ */ new Set());
|
|
27228
|
-
|
|
27490
|
+
if (reachedLimit) {
|
|
27491
|
+
toast.error("One or more items reached their maximum purchase limit");
|
|
27492
|
+
} else {
|
|
27493
|
+
toast.success("Added to cart");
|
|
27494
|
+
}
|
|
27229
27495
|
}
|
|
27230
27496
|
__name(addStagedToCart, "addStagedToCart");
|
|
27231
27497
|
function updateQty(key, quantity) {
|
|
27232
|
-
const
|
|
27498
|
+
const line = lines.find((l) => l.key === key);
|
|
27499
|
+
const hit = line ? productCache.current.get(line.productId) : null;
|
|
27500
|
+
const maxAllowed = typeof hit?.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27501
|
+
const parsed = Math.max(1, Math.floor(quantity) || 1);
|
|
27502
|
+
const q = Math.min(maxAllowed, parsed);
|
|
27503
|
+
if (parsed > maxAllowed) {
|
|
27504
|
+
toast.error(`Maximum purchase limit for "${line?.label ?? "this product"}" is ${maxAllowed}`);
|
|
27505
|
+
}
|
|
27233
27506
|
setLines((prev) => prev.map((l) => l.key === key ? {
|
|
27234
27507
|
...l,
|
|
27235
27508
|
quantity: q
|
|
@@ -27279,6 +27552,13 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27279
27552
|
toast.error("Add at least one product to the cart");
|
|
27280
27553
|
return;
|
|
27281
27554
|
}
|
|
27555
|
+
for (const line of lines) {
|
|
27556
|
+
const hit = productCache.current.get(line.productId);
|
|
27557
|
+
if (hit?.maxPurchaseLimit && line.quantity > hit.maxPurchaseLimit) {
|
|
27558
|
+
toast.error(`Quantity for "${line.label}" cannot exceed maximum allowed limit of ${hit.maxPurchaseLimit}`);
|
|
27559
|
+
return;
|
|
27560
|
+
}
|
|
27561
|
+
}
|
|
27282
27562
|
const unknown = preview?.lines.filter((l) => !l.found) ?? [];
|
|
27283
27563
|
if (unknown.length > 0) {
|
|
27284
27564
|
toast.error(`One or more items could not be validated: ${unknown.map((u) => u.productName).join(", ")}`);
|
|
@@ -27941,6 +28221,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27941
28221
|
}, /* @__PURE__ */ React.createElement(Input, {
|
|
27942
28222
|
type: "number",
|
|
27943
28223
|
min: 1,
|
|
28224
|
+
max: productCache.current.get(line.productId)?.maxPurchaseLimit ?? void 0,
|
|
27944
28225
|
className: "h-8 w-14 ml-auto text-right",
|
|
27945
28226
|
value: line.quantity,
|
|
27946
28227
|
onChange: /* @__PURE__ */ __name((e) => updateQty(line.key, Number(e.target.value)), "onChange"),
|
|
@@ -30541,9 +30822,10 @@ function SaveButton({ pageId, pageData, existingSeoId, onSeoIdChange, onSaved, c
|
|
|
30541
30822
|
}
|
|
30542
30823
|
}
|
|
30543
30824
|
}
|
|
30825
|
+
const normalizedSlug = normalizeSlug(pageData.slug);
|
|
30544
30826
|
const payload = {
|
|
30545
30827
|
title: pageData.title,
|
|
30546
|
-
slug:
|
|
30828
|
+
slug: normalizedSlug,
|
|
30547
30829
|
content,
|
|
30548
30830
|
published: pageData.published
|
|
30549
30831
|
};
|
|
@@ -30783,7 +31065,8 @@ function PageBuilderPage({ pageId }) {
|
|
|
30783
31065
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
30784
31066
|
}, "Slug *"), /* @__PURE__ */ React26__default.createElement(Input, {
|
|
30785
31067
|
value: slug,
|
|
30786
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
31068
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31069
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
30787
31070
|
placeholder: "page-url-slug",
|
|
30788
31071
|
className: "h-8 text-sm"
|
|
30789
31072
|
})))), /* @__PURE__ */ React26__default.createElement(RightSidebar, {
|
|
@@ -30820,6 +31103,7 @@ var init_PageBuilderPage = __esm({
|
|
|
30820
31103
|
init_admin_config_context();
|
|
30821
31104
|
init_registry();
|
|
30822
31105
|
init_ImageOrUrlField();
|
|
31106
|
+
init_slug_sanitizer();
|
|
30823
31107
|
__name(createSelectable, "createSelectable");
|
|
30824
31108
|
__name(buildEditorResolver, "buildEditorResolver");
|
|
30825
31109
|
__name(getIcon, "getIcon");
|
|
@@ -31053,7 +31337,8 @@ function BrandEditPage({ brandId }) {
|
|
|
31053
31337
|
]);
|
|
31054
31338
|
return;
|
|
31055
31339
|
}
|
|
31056
|
-
|
|
31340
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
31341
|
+
if (!normalizedSlug) {
|
|
31057
31342
|
setErrors([
|
|
31058
31343
|
"Slug is required"
|
|
31059
31344
|
]);
|
|
@@ -31061,10 +31346,10 @@ function BrandEditPage({ brandId }) {
|
|
|
31061
31346
|
}
|
|
31062
31347
|
setSaving(true);
|
|
31063
31348
|
try {
|
|
31064
|
-
const savedSeoId = await saveSeo(seo,
|
|
31349
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
31065
31350
|
const payload = {
|
|
31066
31351
|
name: name.trim(),
|
|
31067
|
-
slug:
|
|
31352
|
+
slug: normalizedSlug,
|
|
31068
31353
|
description: description || null,
|
|
31069
31354
|
logo: logo || null,
|
|
31070
31355
|
active,
|
|
@@ -31154,7 +31439,9 @@ function BrandEditPage({ brandId }) {
|
|
|
31154
31439
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
31155
31440
|
type: "text",
|
|
31156
31441
|
value: slug,
|
|
31157
|
-
|
|
31442
|
+
placeholder: "brand-slug",
|
|
31443
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31444
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
31158
31445
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm",
|
|
31159
31446
|
required: true
|
|
31160
31447
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -31214,6 +31501,7 @@ var init_BrandEditPage = __esm({
|
|
|
31214
31501
|
init_DetailPageHeader();
|
|
31215
31502
|
init_vendor_scope();
|
|
31216
31503
|
init_ImageOrUrlField();
|
|
31504
|
+
init_slug_sanitizer();
|
|
31217
31505
|
isCreate = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
31218
31506
|
__name(BrandEditPage, "BrandEditPage");
|
|
31219
31507
|
}
|
|
@@ -32678,11 +32966,21 @@ function ProductEditPage({ productId }) {
|
|
|
32678
32966
|
const pcData = await pcRes.json();
|
|
32679
32967
|
const pcs = Array.isArray(pcData.data) ? pcData.data : [];
|
|
32680
32968
|
if (pcs.length > 0) {
|
|
32681
|
-
|
|
32682
|
-
|
|
32683
|
-
|
|
32684
|
-
|
|
32685
|
-
|
|
32969
|
+
const validTaxPcs = pcs.filter((p) => p.taxId != null && Number(p.taxId) > 0);
|
|
32970
|
+
if (validTaxPcs.length > 0) {
|
|
32971
|
+
setTaxRows(validTaxPcs.map((p) => ({
|
|
32972
|
+
taxId: p.taxId,
|
|
32973
|
+
rate: p.rate != null && p.rate !== "" ? String(p.rate) : ""
|
|
32974
|
+
})));
|
|
32975
|
+
} else if (!cancelled) {
|
|
32976
|
+
setTaxRows([
|
|
32977
|
+
{
|
|
32978
|
+
taxId: "",
|
|
32979
|
+
rate: ""
|
|
32980
|
+
}
|
|
32981
|
+
]);
|
|
32982
|
+
}
|
|
32983
|
+
const firstRefund = pcs.find((p) => p.refundPolicyId != null)?.refundPolicyId;
|
|
32686
32984
|
setRefundPolicyId(firstRefund != null ? Number(firstRefund) : null);
|
|
32687
32985
|
} else if (!cancelled) {
|
|
32688
32986
|
setTaxRows([
|
|
@@ -32691,6 +32989,7 @@ function ProductEditPage({ productId }) {
|
|
|
32691
32989
|
rate: ""
|
|
32692
32990
|
}
|
|
32693
32991
|
]);
|
|
32992
|
+
setRefundPolicyId(null);
|
|
32694
32993
|
}
|
|
32695
32994
|
}
|
|
32696
32995
|
const paRes = await fetch(`/api/product_attributes?productId=${sourceProductId}&limit=100`);
|
|
@@ -33067,14 +33366,7 @@ function ProductEditPage({ productId }) {
|
|
|
33067
33366
|
if (a == null || b == null) return true;
|
|
33068
33367
|
return Math.abs(a - b) > 1e-6;
|
|
33069
33368
|
}, "ratesDiffer");
|
|
33070
|
-
const
|
|
33071
|
-
for (const row of taxRows) {
|
|
33072
|
-
if (row.taxId === "") continue;
|
|
33073
|
-
wantedConfig.set(row.taxId, {
|
|
33074
|
-
rate: parseTaxRate(row.rate),
|
|
33075
|
-
refundPolicyId
|
|
33076
|
-
});
|
|
33077
|
-
}
|
|
33369
|
+
const validTaxRows = taxRows.filter((row) => row.taxId !== "");
|
|
33078
33370
|
console.log("[product_config rows to save]:", taxRows, "refundPolicyId:", refundPolicyId);
|
|
33079
33371
|
const pcListRes = await fetch(`/api/product_config?productId=${savedId}&limit=200`);
|
|
33080
33372
|
const pcListData = pcListRes.ok ? await pcListRes.json() : {
|
|
@@ -33082,17 +33374,60 @@ function ProductEditPage({ productId }) {
|
|
|
33082
33374
|
};
|
|
33083
33375
|
console.log("[product existing pc rows]:", pcListData);
|
|
33084
33376
|
const existingPc = Array.isArray(pcListData.data) ? pcListData.data : [];
|
|
33085
|
-
|
|
33086
|
-
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33377
|
+
if (validTaxRows.length > 0) {
|
|
33378
|
+
const wantedTaxIds = new Set(validTaxRows.map((r) => Number(r.taxId)));
|
|
33379
|
+
for (const ep of existingPc) {
|
|
33380
|
+
if (ep.taxId == null || !wantedTaxIds.has(Number(ep.taxId))) {
|
|
33381
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33382
|
+
method: "DELETE"
|
|
33383
|
+
});
|
|
33384
|
+
}
|
|
33090
33385
|
}
|
|
33091
|
-
|
|
33092
|
-
|
|
33093
|
-
|
|
33094
|
-
|
|
33095
|
-
|
|
33386
|
+
for (const row of validTaxRows) {
|
|
33387
|
+
const taxId = Number(row.taxId);
|
|
33388
|
+
const rate = parseTaxRate(row.rate);
|
|
33389
|
+
const ep = existingPc.find((e) => e.taxId != null && Number(e.taxId) === taxId);
|
|
33390
|
+
if (!ep) {
|
|
33391
|
+
await fetch("/api/product_config", {
|
|
33392
|
+
method: "POST",
|
|
33393
|
+
headers: {
|
|
33394
|
+
"Content-Type": "application/json"
|
|
33395
|
+
},
|
|
33396
|
+
body: JSON.stringify({
|
|
33397
|
+
productId: Number(savedId),
|
|
33398
|
+
taxId,
|
|
33399
|
+
rate,
|
|
33400
|
+
refundPolicyId
|
|
33401
|
+
})
|
|
33402
|
+
});
|
|
33403
|
+
} else {
|
|
33404
|
+
const existingRate = ep.rate == null || String(ep.rate).trim() === "" ? null : Number(ep.rate);
|
|
33405
|
+
const er = Number.isFinite(existingRate) ? existingRate : null;
|
|
33406
|
+
const policyChanged = ep.refundPolicyId !== refundPolicyId;
|
|
33407
|
+
if (ratesDiffer(er, rate) || policyChanged) {
|
|
33408
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33409
|
+
method: "PUT",
|
|
33410
|
+
headers: {
|
|
33411
|
+
"Content-Type": "application/json"
|
|
33412
|
+
},
|
|
33413
|
+
body: JSON.stringify({
|
|
33414
|
+
rate,
|
|
33415
|
+
refundPolicyId
|
|
33416
|
+
})
|
|
33417
|
+
});
|
|
33418
|
+
}
|
|
33419
|
+
}
|
|
33420
|
+
}
|
|
33421
|
+
} else if (refundPolicyId != null) {
|
|
33422
|
+
const nullTaxRow = existingPc.find((e) => e.taxId == null);
|
|
33423
|
+
for (const ep of existingPc) {
|
|
33424
|
+
if (ep.id !== nullTaxRow?.id) {
|
|
33425
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33426
|
+
method: "DELETE"
|
|
33427
|
+
});
|
|
33428
|
+
}
|
|
33429
|
+
}
|
|
33430
|
+
if (!nullTaxRow) {
|
|
33096
33431
|
await fetch("/api/product_config", {
|
|
33097
33432
|
method: "POST",
|
|
33098
33433
|
headers: {
|
|
@@ -33100,27 +33435,27 @@ function ProductEditPage({ productId }) {
|
|
|
33100
33435
|
},
|
|
33101
33436
|
body: JSON.stringify({
|
|
33102
33437
|
productId: Number(savedId),
|
|
33103
|
-
taxId,
|
|
33104
|
-
rate:
|
|
33105
|
-
refundPolicyId
|
|
33438
|
+
taxId: null,
|
|
33439
|
+
rate: null,
|
|
33440
|
+
refundPolicyId
|
|
33106
33441
|
})
|
|
33107
33442
|
});
|
|
33108
|
-
} else {
|
|
33109
|
-
|
|
33110
|
-
|
|
33111
|
-
|
|
33112
|
-
|
|
33113
|
-
|
|
33114
|
-
|
|
33115
|
-
|
|
33116
|
-
|
|
33117
|
-
|
|
33118
|
-
|
|
33119
|
-
|
|
33120
|
-
|
|
33121
|
-
|
|
33122
|
-
|
|
33123
|
-
}
|
|
33443
|
+
} else if (nullTaxRow.refundPolicyId !== refundPolicyId) {
|
|
33444
|
+
await fetch(`/api/product_config/${nullTaxRow.id}`, {
|
|
33445
|
+
method: "PUT",
|
|
33446
|
+
headers: {
|
|
33447
|
+
"Content-Type": "application/json"
|
|
33448
|
+
},
|
|
33449
|
+
body: JSON.stringify({
|
|
33450
|
+
refundPolicyId
|
|
33451
|
+
})
|
|
33452
|
+
});
|
|
33453
|
+
}
|
|
33454
|
+
} else {
|
|
33455
|
+
for (const ep of existingPc) {
|
|
33456
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33457
|
+
method: "DELETE"
|
|
33458
|
+
});
|
|
33124
33459
|
}
|
|
33125
33460
|
}
|
|
33126
33461
|
if (hasVariants) {
|
|
@@ -34036,7 +34371,8 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34036
34371
|
]);
|
|
34037
34372
|
return;
|
|
34038
34373
|
}
|
|
34039
|
-
|
|
34374
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
34375
|
+
if (!normalizedSlug) {
|
|
34040
34376
|
setErrors([
|
|
34041
34377
|
"Slug is required"
|
|
34042
34378
|
]);
|
|
@@ -34044,10 +34380,10 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34044
34380
|
}
|
|
34045
34381
|
setSaving(true);
|
|
34046
34382
|
try {
|
|
34047
|
-
const savedSeoId = await saveSeo(seo,
|
|
34383
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
34048
34384
|
const payload = {
|
|
34049
34385
|
name: name.trim(),
|
|
34050
|
-
slug:
|
|
34386
|
+
slug: normalizedSlug,
|
|
34051
34387
|
hsn: hsn.trim() || null,
|
|
34052
34388
|
categoryId: categoryId || null,
|
|
34053
34389
|
brandId: brandId || null,
|
|
@@ -34216,7 +34552,9 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34216
34552
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
34217
34553
|
type: "text",
|
|
34218
34554
|
value: slug,
|
|
34219
|
-
|
|
34555
|
+
placeholder: "collection-slug",
|
|
34556
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
34557
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
34220
34558
|
className: inputCls4,
|
|
34221
34559
|
required: true
|
|
34222
34560
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -34452,6 +34790,7 @@ var init_CollectionEditPage = __esm({
|
|
|
34452
34790
|
init_admin_config_context();
|
|
34453
34791
|
init_category_related_product_labels();
|
|
34454
34792
|
init_ImageOrUrlField();
|
|
34793
|
+
init_slug_sanitizer();
|
|
34455
34794
|
isCreate3 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
34456
34795
|
emptySlide = /* @__PURE__ */ __name(() => ({
|
|
34457
34796
|
url: "",
|
|
@@ -35631,7 +35970,9 @@ var init_event_entity_types = __esm({
|
|
|
35631
35970
|
// src/admin/pages/EventEditPage.tsx
|
|
35632
35971
|
var EventEditPage_exports = {};
|
|
35633
35972
|
__export(EventEditPage_exports, {
|
|
35634
|
-
default: () => EventEditPage
|
|
35973
|
+
default: () => EventEditPage,
|
|
35974
|
+
normalizeSlug: () => normalizeSlug2,
|
|
35975
|
+
sanitizeSlugInput: () => sanitizeSlugInput2
|
|
35635
35976
|
});
|
|
35636
35977
|
function RequiredLabel({ children }) {
|
|
35637
35978
|
return /* @__PURE__ */ React.createElement("label", {
|
|
@@ -35640,6 +35981,12 @@ function RequiredLabel({ children }) {
|
|
|
35640
35981
|
className: "text-red-600"
|
|
35641
35982
|
}, "*"));
|
|
35642
35983
|
}
|
|
35984
|
+
function sanitizeSlugInput2(value) {
|
|
35985
|
+
return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-");
|
|
35986
|
+
}
|
|
35987
|
+
function normalizeSlug2(value) {
|
|
35988
|
+
return sanitizeSlugInput2(value).replace(/^-+|-+$/g, "");
|
|
35989
|
+
}
|
|
35643
35990
|
function toIsoOrNull(value, timezone) {
|
|
35644
35991
|
const trimmed = value.trim();
|
|
35645
35992
|
if (!trimmed) return null;
|
|
@@ -35730,7 +36077,7 @@ function EventEditPage({ eventId }) {
|
|
|
35730
36077
|
const [supportContact, setSupportContact] = useState("");
|
|
35731
36078
|
const [allowGroupOrders, setAllowGroupOrders] = useState(false);
|
|
35732
36079
|
const [sendIndividualTicketPDFToAttendees, setSendIndividualTicketPDFToAttendees] = useState(false);
|
|
35733
|
-
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = useState("");
|
|
36080
|
+
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = useState("1");
|
|
35734
36081
|
const [sponsors, setSponsors] = useState([]);
|
|
35735
36082
|
const [agenda, setAgenda] = useState([]);
|
|
35736
36083
|
const [workshops, setWorkshops] = useState([]);
|
|
@@ -35856,9 +36203,10 @@ function EventEditPage({ eventId }) {
|
|
|
35856
36203
|
}
|
|
35857
36204
|
setOfficialWebsiteUrl(data.officialWebsiteUrl ?? "");
|
|
35858
36205
|
setSupportContact(data.supportContact ?? "");
|
|
35859
|
-
|
|
36206
|
+
const loadedAllowGroup = data.allowGroupOrders ?? false;
|
|
36207
|
+
setAllowGroupOrders(loadedAllowGroup);
|
|
35860
36208
|
setSendIndividualTicketPDFToAttendees(data.sendIndividualTicketPDFToAttendees ?? false);
|
|
35861
|
-
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : "");
|
|
36209
|
+
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : loadedAllowGroup ? "10" : "1");
|
|
35862
36210
|
setSponsors(parseNamedListFromApi(data.sponsors, "sponsor"));
|
|
35863
36211
|
setAgenda(parseNamedListFromApi(data.agenda, "agenda"));
|
|
35864
36212
|
setWorkshops(parseNamedListFromApi(data.workshops, "workshop"));
|
|
@@ -35904,8 +36252,13 @@ function EventEditPage({ eventId }) {
|
|
|
35904
36252
|
]);
|
|
35905
36253
|
const buildPayload = /* @__PURE__ */ __name(() => {
|
|
35906
36254
|
const nextErrors = [];
|
|
36255
|
+
const normalizedSlug = normalizeSlug2(slug);
|
|
35907
36256
|
if (!name.trim()) nextErrors.push("Name is required");
|
|
35908
|
-
if (!
|
|
36257
|
+
if (!normalizedSlug) {
|
|
36258
|
+
nextErrors.push("Slug is required");
|
|
36259
|
+
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalizedSlug)) {
|
|
36260
|
+
nextErrors.push("Slug must contain only lowercase letters, numbers, and hyphens without leading or trailing hyphens or slashes");
|
|
36261
|
+
}
|
|
35909
36262
|
if (!startDate.trim()) nextErrors.push("Event Start Date & Time is required");
|
|
35910
36263
|
if (!endDate.trim()) nextErrors.push("Event End Date & Time is required");
|
|
35911
36264
|
if (startDate.trim() && !timezone.trim()) {
|
|
@@ -35931,6 +36284,20 @@ function EventEditPage({ eventId }) {
|
|
|
35931
36284
|
nextErrors.push("Event End Date & Time must be after Event Start Date & Time");
|
|
35932
36285
|
}
|
|
35933
36286
|
}
|
|
36287
|
+
if (registrationOpensAt.trim() && registrationClosesAt.trim()) {
|
|
36288
|
+
const regOpen = new Date(toIsoOrNull(registrationOpensAt, timezone) ?? "");
|
|
36289
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36290
|
+
if (!Number.isNaN(regOpen.getTime()) && !Number.isNaN(regClose.getTime()) && regClose < regOpen) {
|
|
36291
|
+
nextErrors.push("Registration Closes Date & Time must be after Registration Opens Date & Time");
|
|
36292
|
+
}
|
|
36293
|
+
}
|
|
36294
|
+
if (registrationClosesAt.trim() && endDate.trim()) {
|
|
36295
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36296
|
+
const end = new Date(toIsoOrNull(endDate, timezone) ?? "");
|
|
36297
|
+
if (!Number.isNaN(regClose.getTime()) && !Number.isNaN(end.getTime()) && regClose > end) {
|
|
36298
|
+
nextErrors.push("Registration cannot close after Event End Date & Time");
|
|
36299
|
+
}
|
|
36300
|
+
}
|
|
35934
36301
|
if (additionalVenueDetails.length > ADDITIONAL_VENUE_MAX_CHARS) {
|
|
35935
36302
|
nextErrors.push(`Additional Venue Details must be ${ADDITIONAL_VENUE_MAX_CHARS} characters or fewer`);
|
|
35936
36303
|
}
|
|
@@ -35940,7 +36307,7 @@ function EventEditPage({ eventId }) {
|
|
|
35940
36307
|
}
|
|
35941
36308
|
const payload = {
|
|
35942
36309
|
name: name.trim(),
|
|
35943
|
-
slug:
|
|
36310
|
+
slug: normalizedSlug,
|
|
35944
36311
|
description: description.trim() || null,
|
|
35945
36312
|
isActive: create && vendorPortal && approvalOn ? false : isActive,
|
|
35946
36313
|
comingSoon,
|
|
@@ -35968,7 +36335,7 @@ function EventEditPage({ eventId }) {
|
|
|
35968
36335
|
supportContact: supportContact.trim() || null,
|
|
35969
36336
|
allowGroupOrders,
|
|
35970
36337
|
sendIndividualTicketPDFToAttendees,
|
|
35971
|
-
maxGroupPurchaseQuantity: maxGroupPurchaseQuantity
|
|
36338
|
+
maxGroupPurchaseQuantity: allowGroupOrders ? Number(maxGroupPurchaseQuantity) > 0 ? Number(maxGroupPurchaseQuantity) : 10 : 1,
|
|
35972
36339
|
sponsors: namedListToPayload(sponsors, {
|
|
35973
36340
|
legacySponsorKeys: true
|
|
35974
36341
|
}),
|
|
@@ -36236,9 +36603,16 @@ function EventEditPage({ eventId }) {
|
|
|
36236
36603
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36237
36604
|
className: labelCls6
|
|
36238
36605
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
36606
|
+
id: "event-slug",
|
|
36239
36607
|
type: "text",
|
|
36240
36608
|
value: slug,
|
|
36241
|
-
|
|
36609
|
+
placeholder: "event-slug",
|
|
36610
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36611
|
+
setSlug(sanitizeSlugInput2(e.target.value));
|
|
36612
|
+
}, "onChange"),
|
|
36613
|
+
onBlur: /* @__PURE__ */ __name(() => {
|
|
36614
|
+
setSlug((prev) => normalizeSlug2(prev));
|
|
36615
|
+
}, "onBlur"),
|
|
36242
36616
|
className: inputCls6
|
|
36243
36617
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36244
36618
|
className: labelCls6
|
|
@@ -36498,7 +36872,16 @@ function EventEditPage({ eventId }) {
|
|
|
36498
36872
|
}, "Max group purchase quantity"), /* @__PURE__ */ React.createElement("input", {
|
|
36499
36873
|
type: "number",
|
|
36500
36874
|
value: maxGroupPurchaseQuantity,
|
|
36501
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36875
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36876
|
+
const val = e.target.value;
|
|
36877
|
+
setMaxGroupPurchaseQuantity(val);
|
|
36878
|
+
const num = Number(val);
|
|
36879
|
+
if (Number.isFinite(num) && num > 1) {
|
|
36880
|
+
setAllowGroupOrders(true);
|
|
36881
|
+
} else if (Number.isFinite(num) && num <= 1) {
|
|
36882
|
+
setAllowGroupOrders(false);
|
|
36883
|
+
}
|
|
36884
|
+
}, "onChange"),
|
|
36502
36885
|
className: inputCls6,
|
|
36503
36886
|
min: 1
|
|
36504
36887
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
@@ -36508,7 +36891,18 @@ function EventEditPage({ eventId }) {
|
|
|
36508
36891
|
}, /* @__PURE__ */ React.createElement("input", {
|
|
36509
36892
|
type: "checkbox",
|
|
36510
36893
|
checked: allowGroupOrders,
|
|
36511
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36894
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36895
|
+
const checked = e.target.checked;
|
|
36896
|
+
setAllowGroupOrders(checked);
|
|
36897
|
+
if (!checked) {
|
|
36898
|
+
setMaxGroupPurchaseQuantity("1");
|
|
36899
|
+
} else {
|
|
36900
|
+
const current = Number(maxGroupPurchaseQuantity);
|
|
36901
|
+
if (!Number.isFinite(current) || current <= 1) {
|
|
36902
|
+
setMaxGroupPurchaseQuantity("10");
|
|
36903
|
+
}
|
|
36904
|
+
}
|
|
36905
|
+
}, "onChange"),
|
|
36512
36906
|
className: "h-4 w-4 rounded border-gray-300"
|
|
36513
36907
|
}), /* @__PURE__ */ React.createElement("span", {
|
|
36514
36908
|
className: "text-sm text-gray-900"
|
|
@@ -36582,6 +36976,8 @@ var init_EventEditPage = __esm({
|
|
|
36582
36976
|
labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
|
|
36583
36977
|
inputCls6 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
36584
36978
|
__name(RequiredLabel, "RequiredLabel");
|
|
36979
|
+
__name(sanitizeSlugInput2, "sanitizeSlugInput");
|
|
36980
|
+
__name(normalizeSlug2, "normalizeSlug");
|
|
36585
36981
|
ENTITY_TYPE_OPTIONS = [
|
|
36586
36982
|
...EVENT_ENTITY_TYPE_OPTIONS
|
|
36587
36983
|
];
|
|
@@ -36960,7 +37356,7 @@ function ComboEditPage({ comboId }) {
|
|
|
36960
37356
|
const resolvedEventId = trimmedEventId && /^\d+$/.test(trimmedEventId) ? Number(trimmedEventId) : null;
|
|
36961
37357
|
const payload = {
|
|
36962
37358
|
name: trimmedName,
|
|
36963
|
-
slug: slug.trim()
|
|
37359
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
36964
37360
|
desc: desc || null,
|
|
36965
37361
|
eventId: resolvedEventId,
|
|
36966
37362
|
price,
|
|
@@ -37055,8 +37451,9 @@ function ComboEditPage({ comboId }) {
|
|
|
37055
37451
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
37056
37452
|
type: "text",
|
|
37057
37453
|
value: slug,
|
|
37058
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37059
|
-
|
|
37454
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
37455
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
37456
|
+
placeholder: "combo-slug",
|
|
37060
37457
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
37061
37458
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
37062
37459
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
@@ -37222,6 +37619,7 @@ var init_ComboEditPage = __esm({
|
|
|
37222
37619
|
init_DetailPageHeader();
|
|
37223
37620
|
init_inventory_validation();
|
|
37224
37621
|
init_admin_config_context();
|
|
37622
|
+
init_slug_sanitizer();
|
|
37225
37623
|
isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
37226
37624
|
__name(formatDateTimeLocal, "formatDateTimeLocal");
|
|
37227
37625
|
__name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
|
|
@@ -37285,6 +37683,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37285
37683
|
const create = isCreate6(vendorId);
|
|
37286
37684
|
const [loading, setLoading] = useState(!create);
|
|
37287
37685
|
const [saving, setSaving] = useState(false);
|
|
37686
|
+
const createInFlightRef = useRef(false);
|
|
37288
37687
|
const [errors, setErrors] = useState([]);
|
|
37289
37688
|
const [name, setName] = useState("");
|
|
37290
37689
|
const [legalName, setLegalName] = useState("");
|
|
@@ -37452,7 +37851,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37452
37851
|
const vendorPayload = /* @__PURE__ */ __name(() => ({
|
|
37453
37852
|
name: name.trim(),
|
|
37454
37853
|
legalName: legalName.trim() || null,
|
|
37455
|
-
slug: slug.trim()
|
|
37854
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37456
37855
|
businessType: businessType || null,
|
|
37457
37856
|
description: description.trim() || null,
|
|
37458
37857
|
website: website.trim() || null,
|
|
@@ -37643,7 +38042,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37643
38042
|
router.push(listReturnUrl);
|
|
37644
38043
|
}, "closeInviteDialog");
|
|
37645
38044
|
const handleCreate = /* @__PURE__ */ __name(async () => {
|
|
37646
|
-
|
|
38045
|
+
if (createInFlightRef.current) return;
|
|
37647
38046
|
setErrors([]);
|
|
37648
38047
|
const createMissing = [];
|
|
37649
38048
|
if (!name.trim()) createMissing.push("Store name is required");
|
|
@@ -37651,14 +38050,12 @@ function VendorEditPage({ vendorId }) {
|
|
|
37651
38050
|
if (!ownerEmail.trim()) createMissing.push("Owner email is required");
|
|
37652
38051
|
if (createMissing.length) {
|
|
37653
38052
|
setErrors(createMissing);
|
|
37654
|
-
setSaving(false);
|
|
37655
38053
|
return;
|
|
37656
38054
|
}
|
|
37657
38055
|
if (!termsAccepted) {
|
|
37658
38056
|
setErrors([
|
|
37659
38057
|
"You must confirm that the vendor has accepted the terms and conditions"
|
|
37660
38058
|
]);
|
|
37661
|
-
setSaving(false);
|
|
37662
38059
|
return;
|
|
37663
38060
|
}
|
|
37664
38061
|
const formattedOwnerPhone = formatPhoneWithCountryCode(ownerPhoneCode, ownerPhoneNum);
|
|
@@ -37669,7 +38066,6 @@ function VendorEditPage({ vendorId }) {
|
|
|
37669
38066
|
setErrors([
|
|
37670
38067
|
taxError
|
|
37671
38068
|
]);
|
|
37672
|
-
setSaving(false);
|
|
37673
38069
|
return;
|
|
37674
38070
|
}
|
|
37675
38071
|
const personErr = validatePersonKyc({
|
|
@@ -37682,25 +38078,22 @@ function VendorEditPage({ vendorId }) {
|
|
|
37682
38078
|
setErrors([
|
|
37683
38079
|
personErr
|
|
37684
38080
|
]);
|
|
37685
|
-
setSaving(false);
|
|
37686
38081
|
return;
|
|
37687
38082
|
}
|
|
37688
38083
|
if (!ownerAddressLine1.trim()) {
|
|
37689
38084
|
setErrors([
|
|
37690
38085
|
"Owner address line 1 is required"
|
|
37691
38086
|
]);
|
|
37692
|
-
setSaving(false);
|
|
37693
38087
|
return;
|
|
37694
38088
|
}
|
|
37695
|
-
|
|
37696
|
-
|
|
38089
|
+
createInFlightRef.current = true;
|
|
38090
|
+
setSaving(true);
|
|
37697
38091
|
try {
|
|
37698
38092
|
const res = await fetch("/api/admin/vendors/onboard", {
|
|
37699
38093
|
method: "POST",
|
|
37700
38094
|
headers: {
|
|
37701
38095
|
"Content-Type": "application/json"
|
|
37702
38096
|
},
|
|
37703
|
-
signal: abortController.signal,
|
|
37704
38097
|
body: JSON.stringify({
|
|
37705
38098
|
activation: "invite",
|
|
37706
38099
|
sendOwnerEmail: false,
|
|
@@ -37721,7 +38114,6 @@ function VendorEditPage({ vendorId }) {
|
|
|
37721
38114
|
}
|
|
37722
38115
|
})
|
|
37723
38116
|
});
|
|
37724
|
-
clearTimeout(timeoutId);
|
|
37725
38117
|
const data = await res.json().catch(() => ({}));
|
|
37726
38118
|
if (!res.ok) {
|
|
37727
38119
|
setErrors([
|
|
@@ -37747,17 +38139,11 @@ function VendorEditPage({ vendorId }) {
|
|
|
37747
38139
|
inviteLink
|
|
37748
38140
|
});
|
|
37749
38141
|
} catch (err) {
|
|
37750
|
-
|
|
37751
|
-
|
|
37752
|
-
|
|
37753
|
-
]);
|
|
37754
|
-
} else {
|
|
37755
|
-
setErrors([
|
|
37756
|
-
err instanceof Error && err.message || "Request failed"
|
|
37757
|
-
]);
|
|
37758
|
-
}
|
|
38142
|
+
setErrors([
|
|
38143
|
+
err instanceof Error && err.message || "Request failed"
|
|
38144
|
+
]);
|
|
37759
38145
|
} finally {
|
|
37760
|
-
|
|
38146
|
+
createInFlightRef.current = false;
|
|
37761
38147
|
setSaving(false);
|
|
37762
38148
|
}
|
|
37763
38149
|
}, "handleCreate");
|
|
@@ -37807,7 +38193,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37807
38193
|
signal: abortController.signal,
|
|
37808
38194
|
body: JSON.stringify({
|
|
37809
38195
|
...vendorPayload(),
|
|
37810
|
-
slug: slug.trim(),
|
|
38196
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37811
38197
|
metadata: (() => {
|
|
37812
38198
|
const next = {
|
|
37813
38199
|
...metadata ?? {}
|
|
@@ -37885,13 +38271,15 @@ function VendorEditPage({ vendorId }) {
|
|
|
37885
38271
|
{
|
|
37886
38272
|
label: saving ? "Creating\u2026" : "Create vendor",
|
|
37887
38273
|
icon: Save,
|
|
37888
|
-
onClick: handleCreate
|
|
38274
|
+
onClick: handleCreate,
|
|
38275
|
+
disabled: saving
|
|
37889
38276
|
}
|
|
37890
38277
|
] : [
|
|
37891
38278
|
{
|
|
37892
38279
|
label: saving ? "Saving\u2026" : "Save",
|
|
37893
38280
|
icon: Save,
|
|
37894
|
-
onClick: handleSave
|
|
38281
|
+
onClick: handleSave,
|
|
38282
|
+
disabled: saving
|
|
37895
38283
|
},
|
|
37896
38284
|
{
|
|
37897
38285
|
label: active ? "Deactivate" : "Activate",
|
|
@@ -37928,8 +38316,9 @@ function VendorEditPage({ vendorId }) {
|
|
|
37928
38316
|
}, "Slug ", create ? "(optional)" : "*"), /* @__PURE__ */ React26__default.createElement(Input, {
|
|
37929
38317
|
id: "vendorSlug",
|
|
37930
38318
|
value: slug,
|
|
37931
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37932
|
-
|
|
38319
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
38320
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
38321
|
+
placeholder: "vendor-slug",
|
|
37933
38322
|
className: `mt-1 ${fieldClass}`
|
|
37934
38323
|
})), /* @__PURE__ */ React26__default.createElement("div", null, /* @__PURE__ */ React26__default.createElement(FieldLabel, {
|
|
37935
38324
|
htmlFor: "businessType"
|
|
@@ -38270,6 +38659,7 @@ var init_VendorEditPage = __esm({
|
|
|
38270
38659
|
init_checkbox();
|
|
38271
38660
|
init_dialog();
|
|
38272
38661
|
init_vendor_profile();
|
|
38662
|
+
init_slug_sanitizer();
|
|
38273
38663
|
init_vendor_list_config();
|
|
38274
38664
|
init_vendor_access_denied();
|
|
38275
38665
|
init_vendor_access_denied();
|