@infuro/cms-core 1.0.72 → 1.0.74
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 +543 -120
- package/dist/admin.js +545 -122
- package/dist/api.cjs +37 -37
- package/dist/api.d.cts +13 -6
- package/dist/api.d.ts +13 -6
- package/dist/api.js +5 -5
- 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-BQQMTQ4C.cjs → chunk-25T6HP5T.cjs} +2 -2
- package/dist/{chunk-TTOEY7AH.cjs → chunk-2JV4EDY3.cjs} +3 -3
- package/dist/{chunk-LJ5C4RBF.js → chunk-6TRH3VY7.js} +1 -1
- package/dist/{chunk-4MNVIGVJ.cjs → chunk-D3SR6CYU.cjs} +3 -3
- package/dist/{chunk-PQJIJ4ZX.js → chunk-DAUBLBTP.js} +1 -1
- package/dist/{chunk-SCE2GIKH.js → chunk-DEGN4BTH.js} +9 -0
- package/dist/{chunk-CKTRA3Q2.cjs → chunk-F3FKBNMQ.cjs} +9 -0
- package/dist/{chunk-SRGDHASW.cjs → chunk-H4UIIBFD.cjs} +2571 -2096
- package/dist/{chunk-YHVA5NHI.js → chunk-LUSJITTI.js} +43 -6
- package/dist/{chunk-43UVXBEH.js → chunk-OQOO2JMB.js} +2529 -2054
- package/dist/{chunk-HZZTDM5J.js → chunk-R5HLPH6P.js} +1 -1
- package/dist/{chunk-3LF4RYAJ.js → chunk-X3IJG25M.js} +1 -1
- package/dist/{chunk-2JHGIWH7.cjs → chunk-X5ILLSTD.cjs} +43 -6
- package/dist/{chunk-NIBEGDD4.cjs → chunk-ZBSH4GWB.cjs} +1 -1
- package/dist/{email-queue-MWP4R67H.js → email-queue-5TOJJT3P.js} +3 -3
- package/dist/{email-queue-BJDH2ID7.cjs → email-queue-X2A46VD3.cjs} +7 -7
- package/dist/{emit-order-notification-trigger-TBXAZAPS.js → emit-order-notification-trigger-3RAVWKLG.js} +1 -1
- package/dist/{emit-order-notification-trigger-I4HQSTEN.cjs → emit-order-notification-trigger-MY3KP7CD.cjs} +3 -3
- package/dist/{erp-order-invoice-5O42ZKC5.cjs → erp-order-invoice-23BDWC2H.cjs} +6 -6
- package/dist/{erp-order-invoice-JEQKFXG4.js → erp-order-invoice-SEZZUDMW.js} +2 -2
- package/dist/generate-local-invoice-pdf-V5FHS23Z.js +3 -0
- package/dist/{generate-local-invoice-pdf-2NCA2WBL.cjs → generate-local-invoice-pdf-XYBVKHNP.cjs} +2 -2
- package/dist/index.cjs +243 -243
- package/dist/index.d.cts +31 -9
- package/dist/index.d.ts +31 -9
- package/dist/index.js +10 -10
- package/dist/migrations/1783400000000-MakeProductConfigTaxIdNullable.ts +40 -0
- package/dist/{order-completion-otp-handlers-KHLZQQJX.js → order-completion-otp-handlers-2WOFSORP.js} +4 -4
- package/dist/{order-completion-otp-handlers-2ZKRK5SN.cjs → order-completion-otp-handlers-EWY47XUA.cjs} +6 -6
- package/dist/{order-notification-dispatcher-Z3MXNF4U.js → order-notification-dispatcher-COR2ZHM3.js} +4 -4
- package/dist/{order-notification-dispatcher-37KDVHBM.cjs → order-notification-dispatcher-KTOAMMSD.cjs} +9 -9
- package/package.json +1 -1
- package/dist/generate-local-invoice-pdf-XUH6GYEJ.js +0 -3
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.74" ;
|
|
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
|
});
|
|
@@ -25933,7 +26144,9 @@ function OrderDiscountPanel({ orderLines, currency, contactId, appliedCoupons, o
|
|
|
25933
26144
|
if (!res.ok) return;
|
|
25934
26145
|
const data = await res.json();
|
|
25935
26146
|
const rows = Array.isArray(data?.data) ? data.data : [];
|
|
25936
|
-
|
|
26147
|
+
const now = Date.now();
|
|
26148
|
+
const activeRows = rows.filter((d) => !d.validUntil || new Date(d.validUntil).getTime() > now);
|
|
26149
|
+
if (!cancelled) setDiscounts(activeRows);
|
|
25937
26150
|
} catch {
|
|
25938
26151
|
} finally {
|
|
25939
26152
|
if (!cancelled) setLoading(false);
|
|
@@ -26399,6 +26612,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26399
26612
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/orders";
|
|
26400
26613
|
const [customers, setCustomers] = useState([]);
|
|
26401
26614
|
const [customersLoading, setCustomersLoading] = useState(true);
|
|
26615
|
+
const [selectedRowId, setSelectedRowId] = useState(null);
|
|
26402
26616
|
const [contactId, setContactId] = useState(null);
|
|
26403
26617
|
const [selectedCustomerId, setSelectedCustomerId] = useState(null);
|
|
26404
26618
|
const [contactName, setContactName] = useState("");
|
|
@@ -26702,9 +26916,11 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26702
26916
|
const rows = (Array.isArray(data?.data) ? data.data : []).map((row) => {
|
|
26703
26917
|
const id = Number(row.id);
|
|
26704
26918
|
if (!Number.isFinite(id)) return null;
|
|
26705
|
-
const
|
|
26919
|
+
const rawContactId = Number(row.contactId ?? row.contact?.id);
|
|
26920
|
+
const rawCustomerId = Number(row.customerId ?? row.customer?.id);
|
|
26706
26921
|
return {
|
|
26707
26922
|
id,
|
|
26923
|
+
contactId: Number.isFinite(rawContactId) && rawContactId > 0 ? rawContactId : null,
|
|
26708
26924
|
customerId: Number.isFinite(rawCustomerId) && rawCustomerId > 0 ? rawCustomerId : null,
|
|
26709
26925
|
name: row.name ?? null,
|
|
26710
26926
|
email: row.email ?? null,
|
|
@@ -26722,6 +26938,15 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26722
26938
|
cancelled = true;
|
|
26723
26939
|
};
|
|
26724
26940
|
}, []);
|
|
26941
|
+
useEffect(() => {
|
|
26942
|
+
if (contactId == null && !contactEmail) return;
|
|
26943
|
+
const match = customers.find((c) => contactId != null && c.contactId === contactId || contactEmail && c.email?.toLowerCase() === contactEmail.toLowerCase());
|
|
26944
|
+
if (match) setSelectedRowId(match.id);
|
|
26945
|
+
}, [
|
|
26946
|
+
contactId,
|
|
26947
|
+
contactEmail,
|
|
26948
|
+
customers
|
|
26949
|
+
]);
|
|
26725
26950
|
async function loadCustomerContacts(customerId) {
|
|
26726
26951
|
setCustomerContactsLoading(true);
|
|
26727
26952
|
setCustomerContacts([]);
|
|
@@ -26802,6 +27027,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26802
27027
|
__name(loadContactAddresses, "loadContactAddresses");
|
|
26803
27028
|
function handleCustomerSelect(value) {
|
|
26804
27029
|
if (value === MANUAL_CUSTOMER) {
|
|
27030
|
+
setSelectedRowId(null);
|
|
26805
27031
|
setContactId(null);
|
|
26806
27032
|
setSelectedCustomerId(null);
|
|
26807
27033
|
setCustomerContacts([]);
|
|
@@ -26809,6 +27035,9 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26809
27035
|
setSubContactName("");
|
|
26810
27036
|
setSubContactEmail("");
|
|
26811
27037
|
setSubContactPhone("");
|
|
27038
|
+
setContactName("");
|
|
27039
|
+
setContactEmail("");
|
|
27040
|
+
setContactPhone("");
|
|
26812
27041
|
setBillingAddress({
|
|
26813
27042
|
...emptyAddress
|
|
26814
27043
|
});
|
|
@@ -26817,11 +27046,12 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26817
27046
|
});
|
|
26818
27047
|
return;
|
|
26819
27048
|
}
|
|
26820
|
-
const
|
|
26821
|
-
if (!Number.isFinite(
|
|
26822
|
-
const customer = customers.find((c) => c.id ===
|
|
27049
|
+
const rowId = Number(value);
|
|
27050
|
+
if (!Number.isFinite(rowId)) return;
|
|
27051
|
+
const customer = customers.find((c) => c.id === rowId);
|
|
26823
27052
|
if (!customer) return;
|
|
26824
|
-
|
|
27053
|
+
setSelectedRowId(rowId);
|
|
27054
|
+
setContactId(customer.contactId ?? null);
|
|
26825
27055
|
setSelectedCustomerId(customer.customerId ?? null);
|
|
26826
27056
|
setContactName(customer.name ?? "");
|
|
26827
27057
|
setContactEmail(customer.email ?? "");
|
|
@@ -26832,7 +27062,9 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26832
27062
|
setSubContactPhone("");
|
|
26833
27063
|
setPlaceForSomeoneElse(false);
|
|
26834
27064
|
if (customer.customerId != null) loadCustomerContacts(customer.customerId);
|
|
26835
|
-
if (customer.
|
|
27065
|
+
if (customer.contactId != null) {
|
|
27066
|
+
loadContactAddresses(customer.contactId);
|
|
27067
|
+
} else if (customer.email) {
|
|
26836
27068
|
loadContactAddressesByEmail(customer.email);
|
|
26837
27069
|
} else {
|
|
26838
27070
|
setBillingAddress({
|
|
@@ -26918,14 +27150,55 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
26918
27150
|
status: "available"
|
|
26919
27151
|
});
|
|
26920
27152
|
if (q.length >= 2) params.set("search", q);
|
|
26921
|
-
const res = await
|
|
27153
|
+
const [res, epRes, evRes] = await Promise.all([
|
|
27154
|
+
fetch(`/api/products?${params}`),
|
|
27155
|
+
fetch("/api/event_products?limit=500").catch(() => null),
|
|
27156
|
+
fetch("/api/events?limit=500").catch(() => null)
|
|
27157
|
+
]);
|
|
26922
27158
|
if (!res.ok) {
|
|
26923
27159
|
setProductHits([]);
|
|
26924
27160
|
return;
|
|
26925
27161
|
}
|
|
26926
27162
|
const body = await res.json();
|
|
26927
27163
|
const hits = Array.isArray(body.data) ? body.data : [];
|
|
26928
|
-
|
|
27164
|
+
const eventMap = /* @__PURE__ */ new Map();
|
|
27165
|
+
if (evRes && evRes.ok) {
|
|
27166
|
+
const evBody = await evRes.json().catch(() => ({}));
|
|
27167
|
+
const evList = Array.isArray(evBody.data) ? evBody.data : [];
|
|
27168
|
+
for (const ev of evList) {
|
|
27169
|
+
if (ev && ev.id) eventMap.set(Number(ev.id), ev);
|
|
27170
|
+
}
|
|
27171
|
+
}
|
|
27172
|
+
const productEventLimits = /* @__PURE__ */ new Map();
|
|
27173
|
+
if (epRes && epRes.ok) {
|
|
27174
|
+
const epBody = await epRes.json().catch(() => ({}));
|
|
27175
|
+
const epList = Array.isArray(epBody.data) ? epBody.data : [];
|
|
27176
|
+
for (const ep of epList) {
|
|
27177
|
+
const ev = eventMap.get(Number(ep.eventId));
|
|
27178
|
+
if (ev) {
|
|
27179
|
+
const maxGroup = typeof ev.maxGroupPurchaseQuantity === "number" && Number.isFinite(ev.maxGroupPurchaseQuantity) && ev.maxGroupPurchaseQuantity > 0 ? Math.floor(ev.maxGroupPurchaseQuantity) : null;
|
|
27180
|
+
const allowsGroup = ev.allowGroupOrders !== false;
|
|
27181
|
+
let cap;
|
|
27182
|
+
if (maxGroup !== null && maxGroup > 1) {
|
|
27183
|
+
cap = maxGroup;
|
|
27184
|
+
} else if (!allowsGroup) {
|
|
27185
|
+
cap = 1;
|
|
27186
|
+
} else if (maxGroup !== null) {
|
|
27187
|
+
cap = maxGroup;
|
|
27188
|
+
} else {
|
|
27189
|
+
cap = 999;
|
|
27190
|
+
}
|
|
27191
|
+
productEventLimits.set(Number(ep.productId), cap);
|
|
27192
|
+
}
|
|
27193
|
+
}
|
|
27194
|
+
}
|
|
27195
|
+
hits.forEach((p) => {
|
|
27196
|
+
const cap = productEventLimits.get(p.id);
|
|
27197
|
+
if (cap !== void 0) {
|
|
27198
|
+
p.maxPurchaseLimit = cap;
|
|
27199
|
+
}
|
|
27200
|
+
productCache.current.set(p.id, p);
|
|
27201
|
+
});
|
|
26929
27202
|
setProductHits(hits);
|
|
26930
27203
|
} catch {
|
|
26931
27204
|
setProductHits([]);
|
|
@@ -27202,6 +27475,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27202
27475
|
toast.message("Select one or more products in the list first");
|
|
27203
27476
|
return;
|
|
27204
27477
|
}
|
|
27478
|
+
let reachedLimit = false;
|
|
27205
27479
|
setLines((prev) => {
|
|
27206
27480
|
const next = [
|
|
27207
27481
|
...prev
|
|
@@ -27209,29 +27483,47 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27209
27483
|
for (const id of stagedIds) {
|
|
27210
27484
|
const hit = productCache.current.get(id);
|
|
27211
27485
|
if (!hit) continue;
|
|
27486
|
+
const maxAllowed = typeof hit.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27212
27487
|
const idx = next.findIndex((l) => l.productId === id);
|
|
27213
27488
|
if (idx >= 0) {
|
|
27214
27489
|
const row = next[idx];
|
|
27215
|
-
|
|
27216
|
-
|
|
27217
|
-
|
|
27218
|
-
|
|
27219
|
-
|
|
27220
|
-
|
|
27221
|
-
|
|
27222
|
-
|
|
27223
|
-
|
|
27224
|
-
|
|
27225
|
-
|
|
27490
|
+
if (row.quantity >= maxAllowed) {
|
|
27491
|
+
reachedLimit = true;
|
|
27492
|
+
} else {
|
|
27493
|
+
next[idx] = {
|
|
27494
|
+
...row,
|
|
27495
|
+
quantity: Math.min(maxAllowed, row.quantity + 1)
|
|
27496
|
+
};
|
|
27497
|
+
}
|
|
27498
|
+
} else {
|
|
27499
|
+
next.push({
|
|
27500
|
+
key: String(id),
|
|
27501
|
+
productId: id,
|
|
27502
|
+
label: hit.name ?? `Product #${id}`,
|
|
27503
|
+
sku: hit.sku,
|
|
27504
|
+
quantity: 1
|
|
27505
|
+
});
|
|
27506
|
+
}
|
|
27226
27507
|
}
|
|
27227
27508
|
return next;
|
|
27228
27509
|
});
|
|
27229
27510
|
setStagedIds(/* @__PURE__ */ new Set());
|
|
27230
|
-
|
|
27511
|
+
if (reachedLimit) {
|
|
27512
|
+
toast.error("One or more items reached their maximum purchase limit");
|
|
27513
|
+
} else {
|
|
27514
|
+
toast.success("Added to cart");
|
|
27515
|
+
}
|
|
27231
27516
|
}
|
|
27232
27517
|
__name(addStagedToCart, "addStagedToCart");
|
|
27233
27518
|
function updateQty(key, quantity) {
|
|
27234
|
-
const
|
|
27519
|
+
const line = lines.find((l) => l.key === key);
|
|
27520
|
+
const hit = line ? productCache.current.get(line.productId) : null;
|
|
27521
|
+
const maxAllowed = typeof hit?.maxPurchaseLimit === "number" && hit.maxPurchaseLimit > 0 ? hit.maxPurchaseLimit : 99999;
|
|
27522
|
+
const parsed = Math.max(1, Math.floor(quantity) || 1);
|
|
27523
|
+
const q = Math.min(maxAllowed, parsed);
|
|
27524
|
+
if (parsed > maxAllowed) {
|
|
27525
|
+
toast.error(`Maximum purchase limit for "${line?.label ?? "this product"}" is ${maxAllowed}`);
|
|
27526
|
+
}
|
|
27235
27527
|
setLines((prev) => prev.map((l) => l.key === key ? {
|
|
27236
27528
|
...l,
|
|
27237
27529
|
quantity: q
|
|
@@ -27281,6 +27573,13 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27281
27573
|
toast.error("Add at least one product to the cart");
|
|
27282
27574
|
return;
|
|
27283
27575
|
}
|
|
27576
|
+
for (const line of lines) {
|
|
27577
|
+
const hit = productCache.current.get(line.productId);
|
|
27578
|
+
if (hit?.maxPurchaseLimit && line.quantity > hit.maxPurchaseLimit) {
|
|
27579
|
+
toast.error(`Quantity for "${line.label}" cannot exceed maximum allowed limit of ${hit.maxPurchaseLimit}`);
|
|
27580
|
+
return;
|
|
27581
|
+
}
|
|
27582
|
+
}
|
|
27284
27583
|
const unknown = preview?.lines.filter((l) => !l.found) ?? [];
|
|
27285
27584
|
if (unknown.length > 0) {
|
|
27286
27585
|
toast.error(`One or more items could not be validated: ${unknown.map((u) => u.productName).join(", ")}`);
|
|
@@ -27310,6 +27609,9 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27310
27609
|
const orderContactId = resolvedContactId;
|
|
27311
27610
|
const updatedMetadata = {
|
|
27312
27611
|
...orderMetadata,
|
|
27612
|
+
customerName: effectiveName || void 0,
|
|
27613
|
+
customerEmail: effectiveEmail || void 0,
|
|
27614
|
+
customerPhone: effectivePhone || void 0,
|
|
27313
27615
|
orderDate: orderDate || void 0,
|
|
27314
27616
|
bookingDate: bookingDate || void 0,
|
|
27315
27617
|
serviceDate: bookingDate || void 0,
|
|
@@ -27338,13 +27640,14 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27338
27640
|
})
|
|
27339
27641
|
};
|
|
27340
27642
|
if (orderContactId != null) payload.contactId = orderContactId;
|
|
27341
|
-
if (!placeForSomeoneElse &&
|
|
27643
|
+
if (!placeForSomeoneElse && selectedCustomerId != null) payload.customerId = selectedCustomerId;
|
|
27342
27644
|
if (placeForSomeoneElse && selectedCustomerId != null) {
|
|
27343
27645
|
payload.accountCustomerId = selectedCustomerId;
|
|
27344
27646
|
}
|
|
27345
27647
|
if (coupons.length > 0) payload.discountId = coupons[0].discountId;
|
|
27346
|
-
|
|
27347
|
-
|
|
27648
|
+
const todayIso = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
27649
|
+
if (!editOrderId && orderDate && orderDate !== todayIso) {
|
|
27650
|
+
payload.createdAt = `${orderDate}T${(/* @__PURE__ */ new Date()).toISOString().slice(11)}`;
|
|
27348
27651
|
}
|
|
27349
27652
|
const url = editOrderId ? `/api/orders/${editOrderId}` : "/api/orders";
|
|
27350
27653
|
const method = editOrderId ? "PUT" : "POST";
|
|
@@ -27431,7 +27734,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27431
27734
|
}
|
|
27432
27735
|
__name(handleSubmit, "handleSubmit");
|
|
27433
27736
|
const allVisibleStaged = productHits.length > 0 && productHits.every((p) => stagedIds.has(p.id));
|
|
27434
|
-
const customerSelectValue =
|
|
27737
|
+
const customerSelectValue = selectedRowId != null ? String(selectedRowId) : MANUAL_CUSTOMER;
|
|
27435
27738
|
const subContactSelectValue = subContactId != null ? String(subContactId) : MANUAL_CONTACT;
|
|
27436
27739
|
if (editOrderId && loadingOrder) {
|
|
27437
27740
|
return /* @__PURE__ */ React.createElement("div", {
|
|
@@ -27943,6 +28246,7 @@ function OrderPlacementPage({ editOrderId }) {
|
|
|
27943
28246
|
}, /* @__PURE__ */ React.createElement(Input, {
|
|
27944
28247
|
type: "number",
|
|
27945
28248
|
min: 1,
|
|
28249
|
+
max: productCache.current.get(line.productId)?.maxPurchaseLimit ?? void 0,
|
|
27946
28250
|
className: "h-8 w-14 ml-auto text-right",
|
|
27947
28251
|
value: line.quantity,
|
|
27948
28252
|
onChange: /* @__PURE__ */ __name((e) => updateQty(line.key, Number(e.target.value)), "onChange"),
|
|
@@ -30543,9 +30847,10 @@ function SaveButton({ pageId, pageData, existingSeoId, onSeoIdChange, onSaved, c
|
|
|
30543
30847
|
}
|
|
30544
30848
|
}
|
|
30545
30849
|
}
|
|
30850
|
+
const normalizedSlug = normalizeSlug(pageData.slug);
|
|
30546
30851
|
const payload = {
|
|
30547
30852
|
title: pageData.title,
|
|
30548
|
-
slug:
|
|
30853
|
+
slug: normalizedSlug,
|
|
30549
30854
|
content,
|
|
30550
30855
|
published: pageData.published
|
|
30551
30856
|
};
|
|
@@ -30785,7 +31090,8 @@ function PageBuilderPage({ pageId }) {
|
|
|
30785
31090
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
30786
31091
|
}, "Slug *"), /* @__PURE__ */ React26__default.createElement(Input, {
|
|
30787
31092
|
value: slug,
|
|
30788
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
31093
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31094
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
30789
31095
|
placeholder: "page-url-slug",
|
|
30790
31096
|
className: "h-8 text-sm"
|
|
30791
31097
|
})))), /* @__PURE__ */ React26__default.createElement(RightSidebar, {
|
|
@@ -30822,6 +31128,7 @@ var init_PageBuilderPage = __esm({
|
|
|
30822
31128
|
init_admin_config_context();
|
|
30823
31129
|
init_registry();
|
|
30824
31130
|
init_ImageOrUrlField();
|
|
31131
|
+
init_slug_sanitizer();
|
|
30825
31132
|
__name(createSelectable, "createSelectable");
|
|
30826
31133
|
__name(buildEditorResolver, "buildEditorResolver");
|
|
30827
31134
|
__name(getIcon, "getIcon");
|
|
@@ -31055,7 +31362,8 @@ function BrandEditPage({ brandId }) {
|
|
|
31055
31362
|
]);
|
|
31056
31363
|
return;
|
|
31057
31364
|
}
|
|
31058
|
-
|
|
31365
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
31366
|
+
if (!normalizedSlug) {
|
|
31059
31367
|
setErrors([
|
|
31060
31368
|
"Slug is required"
|
|
31061
31369
|
]);
|
|
@@ -31063,10 +31371,10 @@ function BrandEditPage({ brandId }) {
|
|
|
31063
31371
|
}
|
|
31064
31372
|
setSaving(true);
|
|
31065
31373
|
try {
|
|
31066
|
-
const savedSeoId = await saveSeo(seo,
|
|
31374
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
31067
31375
|
const payload = {
|
|
31068
31376
|
name: name.trim(),
|
|
31069
|
-
slug:
|
|
31377
|
+
slug: normalizedSlug,
|
|
31070
31378
|
description: description || null,
|
|
31071
31379
|
logo: logo || null,
|
|
31072
31380
|
active,
|
|
@@ -31156,7 +31464,9 @@ function BrandEditPage({ brandId }) {
|
|
|
31156
31464
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
31157
31465
|
type: "text",
|
|
31158
31466
|
value: slug,
|
|
31159
|
-
|
|
31467
|
+
placeholder: "brand-slug",
|
|
31468
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
31469
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
31160
31470
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm",
|
|
31161
31471
|
required: true
|
|
31162
31472
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -31216,6 +31526,7 @@ var init_BrandEditPage = __esm({
|
|
|
31216
31526
|
init_DetailPageHeader();
|
|
31217
31527
|
init_vendor_scope();
|
|
31218
31528
|
init_ImageOrUrlField();
|
|
31529
|
+
init_slug_sanitizer();
|
|
31219
31530
|
isCreate = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
31220
31531
|
__name(BrandEditPage, "BrandEditPage");
|
|
31221
31532
|
}
|
|
@@ -32680,11 +32991,21 @@ function ProductEditPage({ productId }) {
|
|
|
32680
32991
|
const pcData = await pcRes.json();
|
|
32681
32992
|
const pcs = Array.isArray(pcData.data) ? pcData.data : [];
|
|
32682
32993
|
if (pcs.length > 0) {
|
|
32683
|
-
|
|
32684
|
-
|
|
32685
|
-
|
|
32686
|
-
|
|
32687
|
-
|
|
32994
|
+
const validTaxPcs = pcs.filter((p) => p.taxId != null && Number(p.taxId) > 0);
|
|
32995
|
+
if (validTaxPcs.length > 0) {
|
|
32996
|
+
setTaxRows(validTaxPcs.map((p) => ({
|
|
32997
|
+
taxId: p.taxId,
|
|
32998
|
+
rate: p.rate != null && p.rate !== "" ? String(p.rate) : ""
|
|
32999
|
+
})));
|
|
33000
|
+
} else if (!cancelled) {
|
|
33001
|
+
setTaxRows([
|
|
33002
|
+
{
|
|
33003
|
+
taxId: "",
|
|
33004
|
+
rate: ""
|
|
33005
|
+
}
|
|
33006
|
+
]);
|
|
33007
|
+
}
|
|
33008
|
+
const firstRefund = pcs.find((p) => p.refundPolicyId != null)?.refundPolicyId;
|
|
32688
33009
|
setRefundPolicyId(firstRefund != null ? Number(firstRefund) : null);
|
|
32689
33010
|
} else if (!cancelled) {
|
|
32690
33011
|
setTaxRows([
|
|
@@ -32693,6 +33014,7 @@ function ProductEditPage({ productId }) {
|
|
|
32693
33014
|
rate: ""
|
|
32694
33015
|
}
|
|
32695
33016
|
]);
|
|
33017
|
+
setRefundPolicyId(null);
|
|
32696
33018
|
}
|
|
32697
33019
|
}
|
|
32698
33020
|
const paRes = await fetch(`/api/product_attributes?productId=${sourceProductId}&limit=100`);
|
|
@@ -33069,14 +33391,7 @@ function ProductEditPage({ productId }) {
|
|
|
33069
33391
|
if (a == null || b == null) return true;
|
|
33070
33392
|
return Math.abs(a - b) > 1e-6;
|
|
33071
33393
|
}, "ratesDiffer");
|
|
33072
|
-
const
|
|
33073
|
-
for (const row of taxRows) {
|
|
33074
|
-
if (row.taxId === "") continue;
|
|
33075
|
-
wantedConfig.set(row.taxId, {
|
|
33076
|
-
rate: parseTaxRate(row.rate),
|
|
33077
|
-
refundPolicyId
|
|
33078
|
-
});
|
|
33079
|
-
}
|
|
33394
|
+
const validTaxRows = taxRows.filter((row) => row.taxId !== "");
|
|
33080
33395
|
console.log("[product_config rows to save]:", taxRows, "refundPolicyId:", refundPolicyId);
|
|
33081
33396
|
const pcListRes = await fetch(`/api/product_config?productId=${savedId}&limit=200`);
|
|
33082
33397
|
const pcListData = pcListRes.ok ? await pcListRes.json() : {
|
|
@@ -33084,17 +33399,60 @@ function ProductEditPage({ productId }) {
|
|
|
33084
33399
|
};
|
|
33085
33400
|
console.log("[product existing pc rows]:", pcListData);
|
|
33086
33401
|
const existingPc = Array.isArray(pcListData.data) ? pcListData.data : [];
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33402
|
+
if (validTaxRows.length > 0) {
|
|
33403
|
+
const wantedTaxIds = new Set(validTaxRows.map((r) => Number(r.taxId)));
|
|
33404
|
+
for (const ep of existingPc) {
|
|
33405
|
+
if (ep.taxId == null || !wantedTaxIds.has(Number(ep.taxId))) {
|
|
33406
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33407
|
+
method: "DELETE"
|
|
33408
|
+
});
|
|
33409
|
+
}
|
|
33092
33410
|
}
|
|
33093
|
-
|
|
33094
|
-
|
|
33095
|
-
|
|
33096
|
-
|
|
33097
|
-
|
|
33411
|
+
for (const row of validTaxRows) {
|
|
33412
|
+
const taxId = Number(row.taxId);
|
|
33413
|
+
const rate = parseTaxRate(row.rate);
|
|
33414
|
+
const ep = existingPc.find((e) => e.taxId != null && Number(e.taxId) === taxId);
|
|
33415
|
+
if (!ep) {
|
|
33416
|
+
await fetch("/api/product_config", {
|
|
33417
|
+
method: "POST",
|
|
33418
|
+
headers: {
|
|
33419
|
+
"Content-Type": "application/json"
|
|
33420
|
+
},
|
|
33421
|
+
body: JSON.stringify({
|
|
33422
|
+
productId: Number(savedId),
|
|
33423
|
+
taxId,
|
|
33424
|
+
rate,
|
|
33425
|
+
refundPolicyId
|
|
33426
|
+
})
|
|
33427
|
+
});
|
|
33428
|
+
} else {
|
|
33429
|
+
const existingRate = ep.rate == null || String(ep.rate).trim() === "" ? null : Number(ep.rate);
|
|
33430
|
+
const er = Number.isFinite(existingRate) ? existingRate : null;
|
|
33431
|
+
const policyChanged = ep.refundPolicyId !== refundPolicyId;
|
|
33432
|
+
if (ratesDiffer(er, rate) || policyChanged) {
|
|
33433
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33434
|
+
method: "PUT",
|
|
33435
|
+
headers: {
|
|
33436
|
+
"Content-Type": "application/json"
|
|
33437
|
+
},
|
|
33438
|
+
body: JSON.stringify({
|
|
33439
|
+
rate,
|
|
33440
|
+
refundPolicyId
|
|
33441
|
+
})
|
|
33442
|
+
});
|
|
33443
|
+
}
|
|
33444
|
+
}
|
|
33445
|
+
}
|
|
33446
|
+
} else if (refundPolicyId != null) {
|
|
33447
|
+
const nullTaxRow = existingPc.find((e) => e.taxId == null);
|
|
33448
|
+
for (const ep of existingPc) {
|
|
33449
|
+
if (ep.id !== nullTaxRow?.id) {
|
|
33450
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33451
|
+
method: "DELETE"
|
|
33452
|
+
});
|
|
33453
|
+
}
|
|
33454
|
+
}
|
|
33455
|
+
if (!nullTaxRow) {
|
|
33098
33456
|
await fetch("/api/product_config", {
|
|
33099
33457
|
method: "POST",
|
|
33100
33458
|
headers: {
|
|
@@ -33102,27 +33460,27 @@ function ProductEditPage({ productId }) {
|
|
|
33102
33460
|
},
|
|
33103
33461
|
body: JSON.stringify({
|
|
33104
33462
|
productId: Number(savedId),
|
|
33105
|
-
taxId,
|
|
33106
|
-
rate:
|
|
33107
|
-
refundPolicyId
|
|
33463
|
+
taxId: null,
|
|
33464
|
+
rate: null,
|
|
33465
|
+
refundPolicyId
|
|
33466
|
+
})
|
|
33467
|
+
});
|
|
33468
|
+
} else if (nullTaxRow.refundPolicyId !== refundPolicyId) {
|
|
33469
|
+
await fetch(`/api/product_config/${nullTaxRow.id}`, {
|
|
33470
|
+
method: "PUT",
|
|
33471
|
+
headers: {
|
|
33472
|
+
"Content-Type": "application/json"
|
|
33473
|
+
},
|
|
33474
|
+
body: JSON.stringify({
|
|
33475
|
+
refundPolicyId
|
|
33108
33476
|
})
|
|
33109
33477
|
});
|
|
33110
|
-
}
|
|
33111
|
-
|
|
33112
|
-
|
|
33113
|
-
|
|
33114
|
-
|
|
33115
|
-
|
|
33116
|
-
method: "PUT",
|
|
33117
|
-
headers: {
|
|
33118
|
-
"Content-Type": "application/json"
|
|
33119
|
-
},
|
|
33120
|
-
body: JSON.stringify({
|
|
33121
|
-
rate: cfg.rate,
|
|
33122
|
-
refundPolicyId: cfg.refundPolicyId
|
|
33123
|
-
})
|
|
33124
|
-
});
|
|
33125
|
-
}
|
|
33478
|
+
}
|
|
33479
|
+
} else {
|
|
33480
|
+
for (const ep of existingPc) {
|
|
33481
|
+
await fetch(`/api/product_config/${ep.id}`, {
|
|
33482
|
+
method: "DELETE"
|
|
33483
|
+
});
|
|
33126
33484
|
}
|
|
33127
33485
|
}
|
|
33128
33486
|
if (hasVariants) {
|
|
@@ -34038,7 +34396,8 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34038
34396
|
]);
|
|
34039
34397
|
return;
|
|
34040
34398
|
}
|
|
34041
|
-
|
|
34399
|
+
const normalizedSlug = normalizeSlug(slug);
|
|
34400
|
+
if (!normalizedSlug) {
|
|
34042
34401
|
setErrors([
|
|
34043
34402
|
"Slug is required"
|
|
34044
34403
|
]);
|
|
@@ -34046,10 +34405,10 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34046
34405
|
}
|
|
34047
34406
|
setSaving(true);
|
|
34048
34407
|
try {
|
|
34049
|
-
const savedSeoId = await saveSeo(seo,
|
|
34408
|
+
const savedSeoId = await saveSeo(seo, normalizedSlug, seoId);
|
|
34050
34409
|
const payload = {
|
|
34051
34410
|
name: name.trim(),
|
|
34052
|
-
slug:
|
|
34411
|
+
slug: normalizedSlug,
|
|
34053
34412
|
hsn: hsn.trim() || null,
|
|
34054
34413
|
categoryId: categoryId || null,
|
|
34055
34414
|
brandId: brandId || null,
|
|
@@ -34218,7 +34577,9 @@ function CollectionEditPage({ collectionId }) {
|
|
|
34218
34577
|
}, "Slug *"), /* @__PURE__ */ React.createElement("input", {
|
|
34219
34578
|
type: "text",
|
|
34220
34579
|
value: slug,
|
|
34221
|
-
|
|
34580
|
+
placeholder: "collection-slug",
|
|
34581
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
34582
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
34222
34583
|
className: inputCls4,
|
|
34223
34584
|
required: true
|
|
34224
34585
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -34454,6 +34815,7 @@ var init_CollectionEditPage = __esm({
|
|
|
34454
34815
|
init_admin_config_context();
|
|
34455
34816
|
init_category_related_product_labels();
|
|
34456
34817
|
init_ImageOrUrlField();
|
|
34818
|
+
init_slug_sanitizer();
|
|
34457
34819
|
isCreate3 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
34458
34820
|
emptySlide = /* @__PURE__ */ __name(() => ({
|
|
34459
34821
|
url: "",
|
|
@@ -35633,7 +35995,9 @@ var init_event_entity_types = __esm({
|
|
|
35633
35995
|
// src/admin/pages/EventEditPage.tsx
|
|
35634
35996
|
var EventEditPage_exports = {};
|
|
35635
35997
|
__export(EventEditPage_exports, {
|
|
35636
|
-
default: () => EventEditPage
|
|
35998
|
+
default: () => EventEditPage,
|
|
35999
|
+
normalizeSlug: () => normalizeSlug2,
|
|
36000
|
+
sanitizeSlugInput: () => sanitizeSlugInput2
|
|
35637
36001
|
});
|
|
35638
36002
|
function RequiredLabel({ children }) {
|
|
35639
36003
|
return /* @__PURE__ */ React.createElement("label", {
|
|
@@ -35642,6 +36006,12 @@ function RequiredLabel({ children }) {
|
|
|
35642
36006
|
className: "text-red-600"
|
|
35643
36007
|
}, "*"));
|
|
35644
36008
|
}
|
|
36009
|
+
function sanitizeSlugInput2(value) {
|
|
36010
|
+
return value.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-");
|
|
36011
|
+
}
|
|
36012
|
+
function normalizeSlug2(value) {
|
|
36013
|
+
return sanitizeSlugInput2(value).replace(/^-+|-+$/g, "");
|
|
36014
|
+
}
|
|
35645
36015
|
function toIsoOrNull(value, timezone) {
|
|
35646
36016
|
const trimmed = value.trim();
|
|
35647
36017
|
if (!trimmed) return null;
|
|
@@ -35732,7 +36102,7 @@ function EventEditPage({ eventId }) {
|
|
|
35732
36102
|
const [supportContact, setSupportContact] = useState("");
|
|
35733
36103
|
const [allowGroupOrders, setAllowGroupOrders] = useState(false);
|
|
35734
36104
|
const [sendIndividualTicketPDFToAttendees, setSendIndividualTicketPDFToAttendees] = useState(false);
|
|
35735
|
-
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = useState("");
|
|
36105
|
+
const [maxGroupPurchaseQuantity, setMaxGroupPurchaseQuantity] = useState("1");
|
|
35736
36106
|
const [sponsors, setSponsors] = useState([]);
|
|
35737
36107
|
const [agenda, setAgenda] = useState([]);
|
|
35738
36108
|
const [workshops, setWorkshops] = useState([]);
|
|
@@ -35858,9 +36228,10 @@ function EventEditPage({ eventId }) {
|
|
|
35858
36228
|
}
|
|
35859
36229
|
setOfficialWebsiteUrl(data.officialWebsiteUrl ?? "");
|
|
35860
36230
|
setSupportContact(data.supportContact ?? "");
|
|
35861
|
-
|
|
36231
|
+
const loadedAllowGroup = data.allowGroupOrders ?? false;
|
|
36232
|
+
setAllowGroupOrders(loadedAllowGroup);
|
|
35862
36233
|
setSendIndividualTicketPDFToAttendees(data.sendIndividualTicketPDFToAttendees ?? false);
|
|
35863
|
-
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : "");
|
|
36234
|
+
setMaxGroupPurchaseQuantity(data.maxGroupPurchaseQuantity != null ? String(data.maxGroupPurchaseQuantity) : loadedAllowGroup ? "10" : "1");
|
|
35864
36235
|
setSponsors(parseNamedListFromApi(data.sponsors, "sponsor"));
|
|
35865
36236
|
setAgenda(parseNamedListFromApi(data.agenda, "agenda"));
|
|
35866
36237
|
setWorkshops(parseNamedListFromApi(data.workshops, "workshop"));
|
|
@@ -35906,8 +36277,13 @@ function EventEditPage({ eventId }) {
|
|
|
35906
36277
|
]);
|
|
35907
36278
|
const buildPayload = /* @__PURE__ */ __name(() => {
|
|
35908
36279
|
const nextErrors = [];
|
|
36280
|
+
const normalizedSlug = normalizeSlug2(slug);
|
|
35909
36281
|
if (!name.trim()) nextErrors.push("Name is required");
|
|
35910
|
-
if (!
|
|
36282
|
+
if (!normalizedSlug) {
|
|
36283
|
+
nextErrors.push("Slug is required");
|
|
36284
|
+
} else if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(normalizedSlug)) {
|
|
36285
|
+
nextErrors.push("Slug must contain only lowercase letters, numbers, and hyphens without leading or trailing hyphens or slashes");
|
|
36286
|
+
}
|
|
35911
36287
|
if (!startDate.trim()) nextErrors.push("Event Start Date & Time is required");
|
|
35912
36288
|
if (!endDate.trim()) nextErrors.push("Event End Date & Time is required");
|
|
35913
36289
|
if (startDate.trim() && !timezone.trim()) {
|
|
@@ -35933,6 +36309,20 @@ function EventEditPage({ eventId }) {
|
|
|
35933
36309
|
nextErrors.push("Event End Date & Time must be after Event Start Date & Time");
|
|
35934
36310
|
}
|
|
35935
36311
|
}
|
|
36312
|
+
if (registrationOpensAt.trim() && registrationClosesAt.trim()) {
|
|
36313
|
+
const regOpen = new Date(toIsoOrNull(registrationOpensAt, timezone) ?? "");
|
|
36314
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36315
|
+
if (!Number.isNaN(regOpen.getTime()) && !Number.isNaN(regClose.getTime()) && regClose < regOpen) {
|
|
36316
|
+
nextErrors.push("Registration Closes Date & Time must be after Registration Opens Date & Time");
|
|
36317
|
+
}
|
|
36318
|
+
}
|
|
36319
|
+
if (registrationClosesAt.trim() && endDate.trim()) {
|
|
36320
|
+
const regClose = new Date(toIsoOrNull(registrationClosesAt, timezone) ?? "");
|
|
36321
|
+
const end = new Date(toIsoOrNull(endDate, timezone) ?? "");
|
|
36322
|
+
if (!Number.isNaN(regClose.getTime()) && !Number.isNaN(end.getTime()) && regClose > end) {
|
|
36323
|
+
nextErrors.push("Registration cannot close after Event End Date & Time");
|
|
36324
|
+
}
|
|
36325
|
+
}
|
|
35936
36326
|
if (additionalVenueDetails.length > ADDITIONAL_VENUE_MAX_CHARS) {
|
|
35937
36327
|
nextErrors.push(`Additional Venue Details must be ${ADDITIONAL_VENUE_MAX_CHARS} characters or fewer`);
|
|
35938
36328
|
}
|
|
@@ -35942,7 +36332,7 @@ function EventEditPage({ eventId }) {
|
|
|
35942
36332
|
}
|
|
35943
36333
|
const payload = {
|
|
35944
36334
|
name: name.trim(),
|
|
35945
|
-
slug:
|
|
36335
|
+
slug: normalizedSlug,
|
|
35946
36336
|
description: description.trim() || null,
|
|
35947
36337
|
isActive: create && vendorPortal && approvalOn ? false : isActive,
|
|
35948
36338
|
comingSoon,
|
|
@@ -35970,7 +36360,7 @@ function EventEditPage({ eventId }) {
|
|
|
35970
36360
|
supportContact: supportContact.trim() || null,
|
|
35971
36361
|
allowGroupOrders,
|
|
35972
36362
|
sendIndividualTicketPDFToAttendees,
|
|
35973
|
-
maxGroupPurchaseQuantity: maxGroupPurchaseQuantity
|
|
36363
|
+
maxGroupPurchaseQuantity: allowGroupOrders ? Number(maxGroupPurchaseQuantity) > 0 ? Number(maxGroupPurchaseQuantity) : 10 : 1,
|
|
35974
36364
|
sponsors: namedListToPayload(sponsors, {
|
|
35975
36365
|
legacySponsorKeys: true
|
|
35976
36366
|
}),
|
|
@@ -36238,9 +36628,16 @@ function EventEditPage({ eventId }) {
|
|
|
36238
36628
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36239
36629
|
className: labelCls6
|
|
36240
36630
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
36631
|
+
id: "event-slug",
|
|
36241
36632
|
type: "text",
|
|
36242
36633
|
value: slug,
|
|
36243
|
-
|
|
36634
|
+
placeholder: "event-slug",
|
|
36635
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36636
|
+
setSlug(sanitizeSlugInput2(e.target.value));
|
|
36637
|
+
}, "onChange"),
|
|
36638
|
+
onBlur: /* @__PURE__ */ __name(() => {
|
|
36639
|
+
setSlug((prev) => normalizeSlug2(prev));
|
|
36640
|
+
}, "onBlur"),
|
|
36244
36641
|
className: inputCls6
|
|
36245
36642
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
36246
36643
|
className: labelCls6
|
|
@@ -36500,7 +36897,16 @@ function EventEditPage({ eventId }) {
|
|
|
36500
36897
|
}, "Max group purchase quantity"), /* @__PURE__ */ React.createElement("input", {
|
|
36501
36898
|
type: "number",
|
|
36502
36899
|
value: maxGroupPurchaseQuantity,
|
|
36503
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36900
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36901
|
+
const val = e.target.value;
|
|
36902
|
+
setMaxGroupPurchaseQuantity(val);
|
|
36903
|
+
const num = Number(val);
|
|
36904
|
+
if (Number.isFinite(num) && num > 1) {
|
|
36905
|
+
setAllowGroupOrders(true);
|
|
36906
|
+
} else if (Number.isFinite(num) && num <= 1) {
|
|
36907
|
+
setAllowGroupOrders(false);
|
|
36908
|
+
}
|
|
36909
|
+
}, "onChange"),
|
|
36504
36910
|
className: inputCls6,
|
|
36505
36911
|
min: 1
|
|
36506
36912
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
@@ -36510,7 +36916,18 @@ function EventEditPage({ eventId }) {
|
|
|
36510
36916
|
}, /* @__PURE__ */ React.createElement("input", {
|
|
36511
36917
|
type: "checkbox",
|
|
36512
36918
|
checked: allowGroupOrders,
|
|
36513
|
-
onChange: /* @__PURE__ */ __name((e) =>
|
|
36919
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
36920
|
+
const checked = e.target.checked;
|
|
36921
|
+
setAllowGroupOrders(checked);
|
|
36922
|
+
if (!checked) {
|
|
36923
|
+
setMaxGroupPurchaseQuantity("1");
|
|
36924
|
+
} else {
|
|
36925
|
+
const current = Number(maxGroupPurchaseQuantity);
|
|
36926
|
+
if (!Number.isFinite(current) || current <= 1) {
|
|
36927
|
+
setMaxGroupPurchaseQuantity("10");
|
|
36928
|
+
}
|
|
36929
|
+
}
|
|
36930
|
+
}, "onChange"),
|
|
36514
36931
|
className: "h-4 w-4 rounded border-gray-300"
|
|
36515
36932
|
}), /* @__PURE__ */ React.createElement("span", {
|
|
36516
36933
|
className: "text-sm text-gray-900"
|
|
@@ -36584,6 +37001,8 @@ var init_EventEditPage = __esm({
|
|
|
36584
37001
|
labelCls6 = "block text-xs font-medium text-gray-600 mb-1";
|
|
36585
37002
|
inputCls6 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
36586
37003
|
__name(RequiredLabel, "RequiredLabel");
|
|
37004
|
+
__name(sanitizeSlugInput2, "sanitizeSlugInput");
|
|
37005
|
+
__name(normalizeSlug2, "normalizeSlug");
|
|
36587
37006
|
ENTITY_TYPE_OPTIONS = [
|
|
36588
37007
|
...EVENT_ENTITY_TYPE_OPTIONS
|
|
36589
37008
|
];
|
|
@@ -36962,7 +37381,7 @@ function ComboEditPage({ comboId }) {
|
|
|
36962
37381
|
const resolvedEventId = trimmedEventId && /^\d+$/.test(trimmedEventId) ? Number(trimmedEventId) : null;
|
|
36963
37382
|
const payload = {
|
|
36964
37383
|
name: trimmedName,
|
|
36965
|
-
slug: slug.trim()
|
|
37384
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
36966
37385
|
desc: desc || null,
|
|
36967
37386
|
eventId: resolvedEventId,
|
|
36968
37387
|
price,
|
|
@@ -37057,8 +37476,9 @@ function ComboEditPage({ comboId }) {
|
|
|
37057
37476
|
}, "Slug"), /* @__PURE__ */ React.createElement("input", {
|
|
37058
37477
|
type: "text",
|
|
37059
37478
|
value: slug,
|
|
37060
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37061
|
-
|
|
37479
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
37480
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
37481
|
+
placeholder: "combo-slug",
|
|
37062
37482
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
37063
37483
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
37064
37484
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
@@ -37224,6 +37644,7 @@ var init_ComboEditPage = __esm({
|
|
|
37224
37644
|
init_DetailPageHeader();
|
|
37225
37645
|
init_inventory_validation();
|
|
37226
37646
|
init_admin_config_context();
|
|
37647
|
+
init_slug_sanitizer();
|
|
37227
37648
|
isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
37228
37649
|
__name(formatDateTimeLocal, "formatDateTimeLocal");
|
|
37229
37650
|
__name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
|
|
@@ -37455,7 +37876,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37455
37876
|
const vendorPayload = /* @__PURE__ */ __name(() => ({
|
|
37456
37877
|
name: name.trim(),
|
|
37457
37878
|
legalName: legalName.trim() || null,
|
|
37458
|
-
slug: slug.trim()
|
|
37879
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37459
37880
|
businessType: businessType || null,
|
|
37460
37881
|
description: description.trim() || null,
|
|
37461
37882
|
website: website.trim() || null,
|
|
@@ -37797,7 +38218,7 @@ function VendorEditPage({ vendorId }) {
|
|
|
37797
38218
|
signal: abortController.signal,
|
|
37798
38219
|
body: JSON.stringify({
|
|
37799
38220
|
...vendorPayload(),
|
|
37800
|
-
slug: slug.trim(),
|
|
38221
|
+
slug: slug.trim() ? normalizeSlug(slug) : void 0,
|
|
37801
38222
|
metadata: (() => {
|
|
37802
38223
|
const next = {
|
|
37803
38224
|
...metadata ?? {}
|
|
@@ -37920,8 +38341,9 @@ function VendorEditPage({ vendorId }) {
|
|
|
37920
38341
|
}, "Slug ", create ? "(optional)" : "*"), /* @__PURE__ */ React26__default.createElement(Input, {
|
|
37921
38342
|
id: "vendorSlug",
|
|
37922
38343
|
value: slug,
|
|
37923
|
-
onChange: /* @__PURE__ */ __name((e) => setSlug(e.target.value), "onChange"),
|
|
37924
|
-
|
|
38344
|
+
onChange: /* @__PURE__ */ __name((e) => setSlug(sanitizeSlugInput(e.target.value)), "onChange"),
|
|
38345
|
+
onBlur: /* @__PURE__ */ __name(() => setSlug((prev) => normalizeSlug(prev)), "onBlur"),
|
|
38346
|
+
placeholder: "vendor-slug",
|
|
37925
38347
|
className: `mt-1 ${fieldClass}`
|
|
37926
38348
|
})), /* @__PURE__ */ React26__default.createElement("div", null, /* @__PURE__ */ React26__default.createElement(FieldLabel, {
|
|
37927
38349
|
htmlFor: "businessType"
|
|
@@ -38262,6 +38684,7 @@ var init_VendorEditPage = __esm({
|
|
|
38262
38684
|
init_checkbox();
|
|
38263
38685
|
init_dialog();
|
|
38264
38686
|
init_vendor_profile();
|
|
38687
|
+
init_slug_sanitizer();
|
|
38265
38688
|
init_vendor_list_config();
|
|
38266
38689
|
init_vendor_access_denied();
|
|
38267
38690
|
init_vendor_access_denied();
|