@infuro/cms-core 1.0.41 → 1.0.43
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/README.md +5 -18
- package/dist/admin.cjs +959 -303
- package/dist/admin.d.cts +14 -2
- package/dist/admin.d.ts +14 -2
- package/dist/admin.js +959 -303
- package/dist/api.cjs +35 -35
- package/dist/api.js +3 -3
- package/dist/auth.cjs +51 -51
- package/dist/auth.js +3 -3
- package/dist/{chunk-UXMDSNIG.js → chunk-BLR6H5GL.js} +1 -1
- package/dist/{chunk-P7QCLE5W.js → chunk-DN65KDIA.js} +11 -1
- package/dist/{chunk-4BG7XYSH.js → chunk-I6NH72MO.js} +1 -1
- package/dist/{chunk-EG4ICILK.js → chunk-IX7X4ILO.js} +811 -143
- package/dist/{chunk-QU554KAZ.cjs → chunk-SCPKMZG5.cjs} +862 -182
- package/dist/{chunk-ETZN4OQI.cjs → chunk-TAHX46EI.cjs} +6 -6
- package/dist/{chunk-WMXPKKXU.cjs → chunk-X6UQFV4X.cjs} +11 -1
- package/dist/{chunk-OIGCAGH7.cjs → chunk-ZMRQ72F6.cjs} +7 -7
- package/dist/index.cjs +290 -242
- package/dist/index.d.cts +110 -5
- package/dist/index.d.ts +110 -5
- package/dist/index.js +6 -6
- package/dist/migrations/1781300000000-BrandIsCatalog.ts +61 -0
- package/dist/migrations/1781400000000-ComboEventIdNullable.ts +30 -0
- package/dist/migrations/1781500000000-ProductApprovalWorkflow.ts +30 -0
- package/dist/migrations/1781600000000-ProductApprovalStatusColumn.ts +53 -0
- package/dist/migrations/1781700000000-EventApprovalWorkflow.ts +32 -0
- package/dist/{rbac-debug-db-QWHOENBR.js → rbac-debug-db-2SGNLANF.js} +1 -1
- package/dist/{rbac-debug-db-KHG4FJC3.cjs → rbac-debug-db-4Z6A425H.cjs} +2 -2
- package/package.json +1 -1
package/dist/admin.js
CHANGED
|
@@ -457,7 +457,7 @@ var init_admin_config_context = __esm({
|
|
|
457
457
|
var CMS_VERSION;
|
|
458
458
|
var init_cms_version = __esm({
|
|
459
459
|
"src/lib/cms-version.ts"() {
|
|
460
|
-
CMS_VERSION = "1.0.
|
|
460
|
+
CMS_VERSION = "1.0.43" ;
|
|
461
461
|
}
|
|
462
462
|
});
|
|
463
463
|
function useCatalogCategories(enabled = true) {
|
|
@@ -567,9 +567,12 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
567
567
|
const sessionUser = session?.user;
|
|
568
568
|
const showVendorOnboard = canOnboardVendors(sessionUser);
|
|
569
569
|
const vendorPortal = isVendorPortalUser(sessionUser);
|
|
570
|
-
const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled } = useContext(AdminConfigContext);
|
|
570
|
+
const { customNavItems, customNavSections = [], storeEnabled, multiVendorEnabled, eventsEnabled, vendorCanCreateCategories, vendorCanCreateCollections, vendorCanCreateBrands } = useContext(AdminConfigContext);
|
|
571
571
|
const showStoreNav = storeEnabled || vendorPortal;
|
|
572
572
|
const showPlatformNav = !vendorPortal;
|
|
573
|
+
const showVendorCategories = !vendorPortal || vendorCanCreateCategories === true;
|
|
574
|
+
const showVendorCollections = !vendorPortal || vendorCanCreateCollections === true;
|
|
575
|
+
const showVendorBrands = !vendorPortal || vendorCanCreateBrands === true;
|
|
573
576
|
const isDrawer = variant === "drawer";
|
|
574
577
|
const { categories: catalogCategories } = useCatalogCategories(showStoreNav);
|
|
575
578
|
searchParams.get("categoryId")?.trim() ?? "";
|
|
@@ -678,17 +681,17 @@ function AdminSidebar({ variant = "sidebar" }) {
|
|
|
678
681
|
className: `${linkCls} ${isActive("/admin/vendors") ? linkActive : linkInactive}`
|
|
679
682
|
}, /* @__PURE__ */ React.createElement(Store, {
|
|
680
683
|
className: `h-4 w-4 mr-2 ${isActive("/admin/vendors") ? iconActive : iconInactive}`
|
|
681
|
-
}), "Vendors")),
|
|
684
|
+
}), "Vendors")), showVendorCategories && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
682
685
|
href: "/admin/product_categories",
|
|
683
686
|
className: `${linkCls} ${isActive("/admin/product_categories") ? linkActive : linkInactive}`
|
|
684
687
|
}, /* @__PURE__ */ React.createElement(FolderTree, {
|
|
685
688
|
className: `h-4 w-4 mr-2 ${isActive("/admin/product_categories") ? iconActive : iconInactive}`
|
|
686
|
-
}), "Categories")), /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
689
|
+
}), "Categories")), showVendorCollections && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
687
690
|
href: "/admin/collections",
|
|
688
691
|
className: `${linkCls} ${isActive("/admin/collections") ? linkActive : linkInactive}`
|
|
689
692
|
}, /* @__PURE__ */ React.createElement(Layers, {
|
|
690
693
|
className: `h-4 w-4 mr-2 ${isActive("/admin/collections") ? iconActive : iconInactive}`
|
|
691
|
-
}), "Collections")), /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
694
|
+
}), "Collections")), showVendorBrands && /* @__PURE__ */ React.createElement("li", null, /* @__PURE__ */ React.createElement(Link2, {
|
|
692
695
|
href: "/admin/brands",
|
|
693
696
|
className: `${linkCls} ${isActive("/admin/brands") ? linkActive : linkInactive}`
|
|
694
697
|
}, /* @__PURE__ */ React.createElement(Building2, {
|
|
@@ -1371,33 +1374,52 @@ function parseBooleanSetting(value) {
|
|
|
1371
1374
|
}
|
|
1372
1375
|
return null;
|
|
1373
1376
|
}
|
|
1374
|
-
function
|
|
1377
|
+
function useMultiVendorSettings() {
|
|
1375
1378
|
const [multiVendorEnabled, setMultiVendorEnabled] = useState(true);
|
|
1379
|
+
const [vendorCanCreateCategories, setVendorCanCreateCategories] = useState(false);
|
|
1380
|
+
const [vendorCanCreateCollections, setVendorCanCreateCollections] = useState(false);
|
|
1381
|
+
const [vendorCanCreateBrands, setVendorCanCreateBrands] = useState(false);
|
|
1382
|
+
const [requireProductApproval, setRequireProductApproval] = useState(false);
|
|
1376
1383
|
useEffect(() => {
|
|
1377
1384
|
fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
1378
1385
|
const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
|
|
1379
1386
|
setMultiVendorEnabled(parsed ?? true);
|
|
1387
|
+
setVendorCanCreateCategories(parseBooleanSetting(data?.vendorCanCreateCategories) === true);
|
|
1388
|
+
setVendorCanCreateCollections(parseBooleanSetting(data?.vendorCanCreateCollections) === true);
|
|
1389
|
+
setVendorCanCreateBrands(parseBooleanSetting(data?.vendorCanCreateBrands) === true);
|
|
1390
|
+
setRequireProductApproval(parseBooleanSetting(data?.requireProductApproval) === true);
|
|
1380
1391
|
}).catch(() => {
|
|
1381
1392
|
});
|
|
1382
1393
|
}, []);
|
|
1383
|
-
return
|
|
1394
|
+
return {
|
|
1395
|
+
multiVendorEnabled,
|
|
1396
|
+
vendorCanCreateCategories,
|
|
1397
|
+
vendorCanCreateCollections,
|
|
1398
|
+
vendorCanCreateBrands,
|
|
1399
|
+
requireProductApproval
|
|
1400
|
+
};
|
|
1384
1401
|
}
|
|
1385
|
-
function
|
|
1402
|
+
function useEventsSettings() {
|
|
1386
1403
|
const [eventsEnabled, setEventsEnabled] = useState(true);
|
|
1404
|
+
const [requireEventApproval, setRequireEventApproval] = useState(false);
|
|
1387
1405
|
useEffect(() => {
|
|
1388
1406
|
fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
1389
1407
|
const parsed = parseBooleanSetting(data?.enabled ?? data?.value ?? data?.isEnabled ?? data?.active ?? data?.state);
|
|
1390
1408
|
setEventsEnabled(parsed ?? true);
|
|
1409
|
+
setRequireEventApproval(parseBooleanSetting(data?.requireEventApproval) === true);
|
|
1391
1410
|
}).catch(() => {
|
|
1392
1411
|
});
|
|
1393
1412
|
}, []);
|
|
1394
|
-
return
|
|
1413
|
+
return {
|
|
1414
|
+
eventsEnabled,
|
|
1415
|
+
requireEventApproval
|
|
1416
|
+
};
|
|
1395
1417
|
}
|
|
1396
1418
|
function AdminLayout({ children, customNavItems = [], customNavSections = [], customCrudConfigs = {}, categoryRelatedProductLabels = {}, renderOrderDetailFooter, theme, themeRegistry, pluginDescriptors = [] }) {
|
|
1397
1419
|
const resolvedTheme = useResolvedTheme(theme, themeRegistry);
|
|
1398
1420
|
const { storeEnabled, currency } = useStoreEnabled();
|
|
1399
|
-
const multiVendorEnabled =
|
|
1400
|
-
const eventsEnabled =
|
|
1421
|
+
const { multiVendorEnabled, vendorCanCreateCategories, vendorCanCreateCollections, vendorCanCreateBrands, requireProductApproval } = useMultiVendorSettings();
|
|
1422
|
+
const { eventsEnabled, requireEventApproval } = useEventsSettings();
|
|
1401
1423
|
const mergedPluginDescriptors = useMemo(() => {
|
|
1402
1424
|
const seen = new Set(pluginDescriptors.map((p) => p.name));
|
|
1403
1425
|
const extra = BUILTIN_PLUGIN_DESCRIPTORS.filter((p) => !seen.has(p.name));
|
|
@@ -1420,6 +1442,11 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
|
|
|
1420
1442
|
storeEnabled,
|
|
1421
1443
|
currency,
|
|
1422
1444
|
multiVendorEnabled,
|
|
1445
|
+
vendorCanCreateCategories,
|
|
1446
|
+
vendorCanCreateCollections,
|
|
1447
|
+
vendorCanCreateBrands,
|
|
1448
|
+
requireProductApproval,
|
|
1449
|
+
requireEventApproval,
|
|
1423
1450
|
eventsEnabled
|
|
1424
1451
|
}), [
|
|
1425
1452
|
customNavItems,
|
|
@@ -1433,6 +1460,11 @@ function AdminLayout({ children, customNavItems = [], customNavSections = [], cu
|
|
|
1433
1460
|
storeEnabled,
|
|
1434
1461
|
currency,
|
|
1435
1462
|
multiVendorEnabled,
|
|
1463
|
+
vendorCanCreateCategories,
|
|
1464
|
+
vendorCanCreateCollections,
|
|
1465
|
+
vendorCanCreateBrands,
|
|
1466
|
+
requireProductApproval,
|
|
1467
|
+
requireEventApproval,
|
|
1436
1468
|
eventsEnabled
|
|
1437
1469
|
]);
|
|
1438
1470
|
return /* @__PURE__ */ React.createElement(AdminConfigContext.Provider, {
|
|
@@ -1469,8 +1501,8 @@ var init_AdminLayout = __esm({
|
|
|
1469
1501
|
__name(useResolvedTheme, "useResolvedTheme");
|
|
1470
1502
|
__name(useStoreEnabled, "useStoreEnabled");
|
|
1471
1503
|
__name(parseBooleanSetting, "parseBooleanSetting");
|
|
1472
|
-
__name(
|
|
1473
|
-
__name(
|
|
1504
|
+
__name(useMultiVendorSettings, "useMultiVendorSettings");
|
|
1505
|
+
__name(useEventsSettings, "useEventsSettings");
|
|
1474
1506
|
__name(AdminLayout, "AdminLayout");
|
|
1475
1507
|
}
|
|
1476
1508
|
});
|
|
@@ -6641,9 +6673,10 @@ var init_CategoryAutocomplete = __esm({
|
|
|
6641
6673
|
__name(CategoryAutocomplete, "CategoryAutocomplete");
|
|
6642
6674
|
}
|
|
6643
6675
|
});
|
|
6644
|
-
function UserAutocomplete({ selectedUserId, onUserChange, placeholder = "Select author...", className = "" }) {
|
|
6676
|
+
function UserAutocomplete({ selectedUserId, onUserChange, placeholder = "Select author...", className = "", groupName = ADMIN_GROUP_NAME }) {
|
|
6645
6677
|
const [inputValue, setInputValue] = useState("");
|
|
6646
6678
|
const [suggestions, setSuggestions] = useState([]);
|
|
6679
|
+
const [selectedUser, setSelectedUser] = useState(null);
|
|
6647
6680
|
const [isLoading, setIsLoading] = useState(false);
|
|
6648
6681
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
6649
6682
|
const inputRef = useRef(null);
|
|
@@ -6652,14 +6685,18 @@ function UserAutocomplete({ selectedUserId, onUserChange, placeholder = "Select
|
|
|
6652
6685
|
setIsLoading(true);
|
|
6653
6686
|
try {
|
|
6654
6687
|
const params = new URLSearchParams();
|
|
6655
|
-
if (query.trim())
|
|
6656
|
-
params.append("search", query);
|
|
6657
|
-
}
|
|
6688
|
+
if (query.trim()) params.append("search", query);
|
|
6658
6689
|
params.append("limit", "50");
|
|
6690
|
+
const group = groupName.trim() || ADMIN_GROUP_NAME;
|
|
6691
|
+
params.append("groupName", group);
|
|
6659
6692
|
const response = await fetch(`/api/users?${params}`);
|
|
6660
6693
|
if (response.ok) {
|
|
6661
6694
|
const data = await response.json();
|
|
6662
|
-
|
|
6695
|
+
const rows = Array.isArray(data.data) ? data.data : [];
|
|
6696
|
+
setSuggestions(rows.filter((u) => {
|
|
6697
|
+
const g = u.group?.name;
|
|
6698
|
+
return g == null || g === group;
|
|
6699
|
+
}));
|
|
6663
6700
|
}
|
|
6664
6701
|
} catch (error) {
|
|
6665
6702
|
console.error("Error fetching users:", error);
|
|
@@ -6673,28 +6710,57 @@ function UserAutocomplete({ selectedUserId, onUserChange, placeholder = "Select
|
|
|
6673
6710
|
}, 300);
|
|
6674
6711
|
return () => clearTimeout(timeoutId);
|
|
6675
6712
|
}, [
|
|
6676
|
-
inputValue
|
|
6713
|
+
inputValue,
|
|
6714
|
+
groupName
|
|
6715
|
+
]);
|
|
6716
|
+
useEffect(() => {
|
|
6717
|
+
if (selectedUserId == null) {
|
|
6718
|
+
setSelectedUser(null);
|
|
6719
|
+
return;
|
|
6720
|
+
}
|
|
6721
|
+
if (selectedUser?.id === selectedUserId) return;
|
|
6722
|
+
let cancelled = false;
|
|
6723
|
+
(async () => {
|
|
6724
|
+
try {
|
|
6725
|
+
const res = await fetch(`/api/users/${selectedUserId}`);
|
|
6726
|
+
if (!res.ok || cancelled) return;
|
|
6727
|
+
const data = await res.json();
|
|
6728
|
+
if (!cancelled && data?.id != null) {
|
|
6729
|
+
setSelectedUser({
|
|
6730
|
+
id: Number(data.id),
|
|
6731
|
+
name: String(data.name ?? ""),
|
|
6732
|
+
email: String(data.email ?? "")
|
|
6733
|
+
});
|
|
6734
|
+
}
|
|
6735
|
+
} catch {
|
|
6736
|
+
}
|
|
6737
|
+
})();
|
|
6738
|
+
return () => {
|
|
6739
|
+
cancelled = true;
|
|
6740
|
+
};
|
|
6741
|
+
}, [
|
|
6742
|
+
selectedUserId,
|
|
6743
|
+
selectedUser?.id
|
|
6677
6744
|
]);
|
|
6678
6745
|
const handleInputChange = /* @__PURE__ */ __name((e) => {
|
|
6679
|
-
|
|
6680
|
-
setInputValue(value);
|
|
6746
|
+
setInputValue(e.target.value);
|
|
6681
6747
|
setShowSuggestions(true);
|
|
6682
6748
|
}, "handleInputChange");
|
|
6683
6749
|
const handleSuggestionSelect = /* @__PURE__ */ __name((user) => {
|
|
6684
6750
|
onUserChange(user.id);
|
|
6751
|
+
setSelectedUser(user);
|
|
6685
6752
|
setInputValue("");
|
|
6686
6753
|
setShowSuggestions(false);
|
|
6687
6754
|
setSuggestions([]);
|
|
6688
6755
|
}, "handleSuggestionSelect");
|
|
6689
6756
|
const handleRemoveUser = /* @__PURE__ */ __name(() => {
|
|
6690
6757
|
onUserChange(null);
|
|
6758
|
+
setSelectedUser(null);
|
|
6691
6759
|
}, "handleRemoveUser");
|
|
6692
6760
|
const handleKeyPress = /* @__PURE__ */ __name((e) => {
|
|
6693
6761
|
if (e.key === "Enter") {
|
|
6694
6762
|
e.preventDefault();
|
|
6695
|
-
if (suggestions.length > 0)
|
|
6696
|
-
handleSuggestionSelect(suggestions[0]);
|
|
6697
|
-
}
|
|
6763
|
+
if (suggestions.length > 0) handleSuggestionSelect(suggestions[0]);
|
|
6698
6764
|
} else if (e.key === "Escape") {
|
|
6699
6765
|
setShowSuggestions(false);
|
|
6700
6766
|
inputRef.current?.blur();
|
|
@@ -6709,14 +6775,13 @@ function UserAutocomplete({ selectedUserId, onUserChange, placeholder = "Select
|
|
|
6709
6775
|
document.addEventListener("mousedown", handleClickOutside);
|
|
6710
6776
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
6711
6777
|
}, []);
|
|
6712
|
-
const selectedUser = suggestions.find((user) => user.id === selectedUserId);
|
|
6713
6778
|
return /* @__PURE__ */ React.createElement("div", {
|
|
6714
6779
|
className: `relative ${className}`
|
|
6715
6780
|
}, selectedUser && /* @__PURE__ */ React.createElement("div", {
|
|
6716
6781
|
className: "mb-2"
|
|
6717
6782
|
}, /* @__PURE__ */ React.createElement(Badge, {
|
|
6718
6783
|
className: "flex items-center gap-1"
|
|
6719
|
-
}, selectedUser.name
|
|
6784
|
+
}, selectedUser.name || selectedUser.email || `User #${selectedUser.id}`, /* @__PURE__ */ React.createElement(X, {
|
|
6720
6785
|
size: 12,
|
|
6721
6786
|
className: "cursor-pointer hover:text-red-500",
|
|
6722
6787
|
onClick: handleRemoveUser
|
|
@@ -6760,6 +6825,7 @@ var init_UserAutocomplete = __esm({
|
|
|
6760
6825
|
"use client";
|
|
6761
6826
|
init_input();
|
|
6762
6827
|
init_badge();
|
|
6828
|
+
init_permission_entities();
|
|
6763
6829
|
__name(UserAutocomplete, "UserAutocomplete");
|
|
6764
6830
|
}
|
|
6765
6831
|
});
|
|
@@ -7190,7 +7256,8 @@ function BlogEditor({ existingBlog, duplicateSource }) {
|
|
|
7190
7256
|
selectedUserId: authorId,
|
|
7191
7257
|
onUserChange: setAuthorId,
|
|
7192
7258
|
placeholder: "Select author...",
|
|
7193
|
-
className: "w-full"
|
|
7259
|
+
className: "w-full",
|
|
7260
|
+
groupName: "Administrator"
|
|
7194
7261
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(ImageUpload, {
|
|
7195
7262
|
value: coverImage,
|
|
7196
7263
|
onChange: setCoverImage,
|
|
@@ -7701,6 +7768,155 @@ var init_ComponentSettings = __esm({
|
|
|
7701
7768
|
__name(ComponentSettings, "ComponentSettings");
|
|
7702
7769
|
}
|
|
7703
7770
|
});
|
|
7771
|
+
function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026", inputClassName = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm", labelClassName = "block text-xs font-medium text-gray-600 mb-1", previewVariant = "banner", maxSizeMb = 10 }) {
|
|
7772
|
+
const fileInputRef = useRef(null);
|
|
7773
|
+
const [isUploading, setIsUploading] = useState(false);
|
|
7774
|
+
const [error, setError] = useState(null);
|
|
7775
|
+
const [lightboxOpen, setLightboxOpen] = useState(false);
|
|
7776
|
+
const previewCls = previewVariant === "logo" ? "h-20 w-20 rounded-md border border-gray-200 bg-white object-contain cursor-pointer" : "max-h-32 w-full rounded-md border border-gray-200 bg-gray-50 object-cover cursor-pointer";
|
|
7777
|
+
const closeLightbox = useCallback(() => setLightboxOpen(false), []);
|
|
7778
|
+
useEffect(() => {
|
|
7779
|
+
if (!lightboxOpen) return;
|
|
7780
|
+
const onKeyDown = /* @__PURE__ */ __name((e) => {
|
|
7781
|
+
if (e.key === "Escape") closeLightbox();
|
|
7782
|
+
}, "onKeyDown");
|
|
7783
|
+
window.addEventListener("keydown", onKeyDown);
|
|
7784
|
+
const prevOverflow = document.body.style.overflow;
|
|
7785
|
+
document.body.style.overflow = "hidden";
|
|
7786
|
+
return () => {
|
|
7787
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
7788
|
+
document.body.style.overflow = prevOverflow;
|
|
7789
|
+
};
|
|
7790
|
+
}, [
|
|
7791
|
+
lightboxOpen,
|
|
7792
|
+
closeLightbox
|
|
7793
|
+
]);
|
|
7794
|
+
const handleUpload = useCallback(async (file) => {
|
|
7795
|
+
setError(null);
|
|
7796
|
+
if (!ACCEPTED_TYPES.includes(file.type)) {
|
|
7797
|
+
setError(`Unsupported file type. Use: ${ACCEPTED_TYPES.map((t) => t.replace("image/", "")).join(", ")}`);
|
|
7798
|
+
return;
|
|
7799
|
+
}
|
|
7800
|
+
if (file.size > maxSizeMb * 1024 * 1024) {
|
|
7801
|
+
setError(`File must be under ${maxSizeMb}MB`);
|
|
7802
|
+
return;
|
|
7803
|
+
}
|
|
7804
|
+
setIsUploading(true);
|
|
7805
|
+
try {
|
|
7806
|
+
const formData = new FormData();
|
|
7807
|
+
formData.append("file", file);
|
|
7808
|
+
const response = await fetch("/api/upload", {
|
|
7809
|
+
method: "POST",
|
|
7810
|
+
body: formData
|
|
7811
|
+
});
|
|
7812
|
+
const data = await response.json();
|
|
7813
|
+
if (!response.ok) {
|
|
7814
|
+
throw new Error(data.error || data.details || "Upload failed");
|
|
7815
|
+
}
|
|
7816
|
+
onChange(data.filePath ?? "");
|
|
7817
|
+
} catch (err) {
|
|
7818
|
+
setError(err instanceof Error ? err.message : "Upload failed");
|
|
7819
|
+
} finally {
|
|
7820
|
+
setIsUploading(false);
|
|
7821
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
7822
|
+
}
|
|
7823
|
+
}, [
|
|
7824
|
+
maxSizeMb,
|
|
7825
|
+
onChange
|
|
7826
|
+
]);
|
|
7827
|
+
const onFileChange = useCallback((e) => {
|
|
7828
|
+
const file = e.target.files?.[0];
|
|
7829
|
+
if (file) void handleUpload(file);
|
|
7830
|
+
}, [
|
|
7831
|
+
handleUpload
|
|
7832
|
+
]);
|
|
7833
|
+
const trimmed = value.trim();
|
|
7834
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
7835
|
+
className: "space-y-2"
|
|
7836
|
+
}, /* @__PURE__ */ React.createElement("label", {
|
|
7837
|
+
className: labelClassName
|
|
7838
|
+
}, label), trimmed ? /* @__PURE__ */ React.createElement("div", {
|
|
7839
|
+
className: "flex items-start gap-3"
|
|
7840
|
+
}, /* @__PURE__ */ React.createElement("img", {
|
|
7841
|
+
src: trimmed,
|
|
7842
|
+
alt: label,
|
|
7843
|
+
className: previewCls,
|
|
7844
|
+
role: "button",
|
|
7845
|
+
tabIndex: 0,
|
|
7846
|
+
title: "Click to enlarge",
|
|
7847
|
+
onClick: /* @__PURE__ */ __name(() => setLightboxOpen(true), "onClick"),
|
|
7848
|
+
onKeyDown: /* @__PURE__ */ __name((e) => {
|
|
7849
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
7850
|
+
e.preventDefault();
|
|
7851
|
+
setLightboxOpen(true);
|
|
7852
|
+
}
|
|
7853
|
+
}, "onKeyDown"),
|
|
7854
|
+
onError: /* @__PURE__ */ __name((e) => {
|
|
7855
|
+
e.currentTarget.style.display = "none";
|
|
7856
|
+
}, "onError")
|
|
7857
|
+
}), /* @__PURE__ */ React.createElement("button", {
|
|
7858
|
+
type: "button",
|
|
7859
|
+
onClick: /* @__PURE__ */ __name(() => onChange(""), "onClick"),
|
|
7860
|
+
className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
|
|
7861
|
+
}, /* @__PURE__ */ React.createElement(X, {
|
|
7862
|
+
className: "h-3 w-3"
|
|
7863
|
+
}), "Clear")) : null, /* @__PURE__ */ React.createElement("div", {
|
|
7864
|
+
className: "flex flex-wrap gap-2"
|
|
7865
|
+
}, /* @__PURE__ */ React.createElement("input", {
|
|
7866
|
+
type: "url",
|
|
7867
|
+
value,
|
|
7868
|
+
onChange: /* @__PURE__ */ __name((e) => {
|
|
7869
|
+
setError(null);
|
|
7870
|
+
onChange(e.target.value);
|
|
7871
|
+
}, "onChange"),
|
|
7872
|
+
placeholder,
|
|
7873
|
+
className: `${inputClassName} min-w-0 flex-1`
|
|
7874
|
+
}), /* @__PURE__ */ React.createElement("input", {
|
|
7875
|
+
ref: fileInputRef,
|
|
7876
|
+
type: "file",
|
|
7877
|
+
accept: ACCEPTED_TYPES.join(","),
|
|
7878
|
+
onChange: onFileChange,
|
|
7879
|
+
className: "hidden",
|
|
7880
|
+
disabled: isUploading
|
|
7881
|
+
}), /* @__PURE__ */ React.createElement("button", {
|
|
7882
|
+
type: "button",
|
|
7883
|
+
onClick: /* @__PURE__ */ __name(() => fileInputRef.current?.click(), "onClick"),
|
|
7884
|
+
disabled: isUploading,
|
|
7885
|
+
className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
|
|
7886
|
+
}, /* @__PURE__ */ React.createElement(Upload, {
|
|
7887
|
+
className: "h-3.5 w-3.5"
|
|
7888
|
+
}), isUploading ? "Uploading\u2026" : "Upload")), error ? /* @__PURE__ */ React.createElement("p", {
|
|
7889
|
+
className: "flex items-center gap-1.5 text-xs text-red-600"
|
|
7890
|
+
}, /* @__PURE__ */ React.createElement(AlertCircle, {
|
|
7891
|
+
className: "h-3.5 w-3.5 shrink-0"
|
|
7892
|
+
}), error) : /* @__PURE__ */ React.createElement("p", {
|
|
7893
|
+
className: "text-xs text-gray-500"
|
|
7894
|
+
}, "Paste a URL or upload an image (PNG, JPG, GIF, WEBP up to ", maxSizeMb, "MB)"), lightboxOpen && trimmed ? /* @__PURE__ */ React.createElement("div", {
|
|
7895
|
+
className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/70 p-4",
|
|
7896
|
+
role: "dialog",
|
|
7897
|
+
"aria-modal": "true",
|
|
7898
|
+
"aria-label": `${label} preview`,
|
|
7899
|
+
onClick: closeLightbox
|
|
7900
|
+
}, /* @__PURE__ */ React.createElement("img", {
|
|
7901
|
+
src: trimmed,
|
|
7902
|
+
alt: label,
|
|
7903
|
+
className: "max-h-[90vh] max-w-[90vw] rounded-md object-contain shadow-lg",
|
|
7904
|
+
onClick: /* @__PURE__ */ __name((e) => e.stopPropagation(), "onClick")
|
|
7905
|
+
})) : null);
|
|
7906
|
+
}
|
|
7907
|
+
var ACCEPTED_TYPES;
|
|
7908
|
+
var init_ImageOrUrlField = __esm({
|
|
7909
|
+
"src/components/Admin/ImageOrUrlField.tsx"() {
|
|
7910
|
+
"use client";
|
|
7911
|
+
ACCEPTED_TYPES = [
|
|
7912
|
+
"image/jpeg",
|
|
7913
|
+
"image/png",
|
|
7914
|
+
"image/gif",
|
|
7915
|
+
"image/webp"
|
|
7916
|
+
];
|
|
7917
|
+
__name(ImageOrUrlField, "ImageOrUrlField");
|
|
7918
|
+
}
|
|
7919
|
+
});
|
|
7704
7920
|
function generateId() {
|
|
7705
7921
|
return `nav_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
7706
7922
|
}
|
|
@@ -8003,22 +8219,16 @@ function NavbarEditor({ config, onChange }) {
|
|
|
8003
8219
|
className: "space-y-6"
|
|
8004
8220
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
8005
8221
|
className: "space-y-3"
|
|
8006
|
-
}, /* @__PURE__ */ React.createElement(
|
|
8007
|
-
|
|
8008
|
-
}, "Logo"), /* @__PURE__ */ React.createElement("div", {
|
|
8009
|
-
className: "flex items-center gap-3"
|
|
8010
|
-
}, config.logo && /* @__PURE__ */ React.createElement("img", {
|
|
8011
|
-
src: config.logo,
|
|
8012
|
-
alt: "Logo",
|
|
8013
|
-
className: "h-10 rounded border object-contain"
|
|
8014
|
-
}), /* @__PURE__ */ React.createElement(Input, {
|
|
8222
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
8223
|
+
label: "Logo",
|
|
8015
8224
|
value: config.logo || "",
|
|
8016
|
-
onChange: /* @__PURE__ */ __name((
|
|
8225
|
+
onChange: /* @__PURE__ */ __name((logo) => onChange({
|
|
8017
8226
|
...config,
|
|
8018
|
-
logo
|
|
8227
|
+
logo
|
|
8019
8228
|
}), "onChange"),
|
|
8229
|
+
previewVariant: "logo",
|
|
8020
8230
|
placeholder: "Logo image URL"
|
|
8021
|
-
}))
|
|
8231
|
+
})), /* @__PURE__ */ React.createElement("div", {
|
|
8022
8232
|
className: "space-y-3"
|
|
8023
8233
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
8024
8234
|
className: "flex items-center justify-between"
|
|
@@ -8057,6 +8267,7 @@ var init_NavbarEditor = __esm({
|
|
|
8057
8267
|
init_button();
|
|
8058
8268
|
init_switch();
|
|
8059
8269
|
init_label();
|
|
8270
|
+
init_ImageOrUrlField();
|
|
8060
8271
|
__name(generateId, "generateId");
|
|
8061
8272
|
__name(NavItemEditor, "NavItemEditor");
|
|
8062
8273
|
__name(updateItemInTree, "updateItemInTree");
|
|
@@ -11005,10 +11216,32 @@ function renderListPrice(value, item) {
|
|
|
11005
11216
|
return `${formatted} ${currency}`;
|
|
11006
11217
|
}
|
|
11007
11218
|
}
|
|
11219
|
+
function renderListThumbnail(url) {
|
|
11220
|
+
const trimmed = url.trim();
|
|
11221
|
+
if (!trimmed) return "\u2014";
|
|
11222
|
+
return createElement("img", {
|
|
11223
|
+
src: trimmed,
|
|
11224
|
+
alt: "",
|
|
11225
|
+
className: "h-10 w-10 rounded border border-gray-200 bg-white object-contain"
|
|
11226
|
+
});
|
|
11227
|
+
}
|
|
11228
|
+
function productListImageUrl(item) {
|
|
11229
|
+
const meta = item.metadata;
|
|
11230
|
+
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return "";
|
|
11231
|
+
const images = meta.images;
|
|
11232
|
+
if (!Array.isArray(images)) return "";
|
|
11233
|
+
const rows = images;
|
|
11234
|
+
const def = rows.find((r) => r?.isDefault && typeof r.url === "string" && r.url.trim());
|
|
11235
|
+
if (def && typeof def.url === "string") return def.url.trim();
|
|
11236
|
+
const first = rows.find((r) => typeof r.url === "string" && r.url.trim());
|
|
11237
|
+
return first && typeof first.url === "string" ? first.url.trim() : "";
|
|
11238
|
+
}
|
|
11008
11239
|
var STORE_CRUD_CONFIGS;
|
|
11009
11240
|
var init_store_crud_configs = __esm({
|
|
11010
11241
|
"src/admin/store-crud-configs.ts"() {
|
|
11011
11242
|
__name(renderListPrice, "renderListPrice");
|
|
11243
|
+
__name(renderListThumbnail, "renderListThumbnail");
|
|
11244
|
+
__name(productListImageUrl, "productListImageUrl");
|
|
11012
11245
|
STORE_CRUD_CONFIGS = {
|
|
11013
11246
|
products: {
|
|
11014
11247
|
title: "Products",
|
|
@@ -11034,9 +11267,40 @@ var init_store_crud_configs = __esm({
|
|
|
11034
11267
|
label: "Out of stock"
|
|
11035
11268
|
}
|
|
11036
11269
|
]
|
|
11270
|
+
},
|
|
11271
|
+
{
|
|
11272
|
+
param: "approvalStatus",
|
|
11273
|
+
label: "Approval",
|
|
11274
|
+
type: "select",
|
|
11275
|
+
options: [
|
|
11276
|
+
{
|
|
11277
|
+
value: "",
|
|
11278
|
+
label: "All"
|
|
11279
|
+
},
|
|
11280
|
+
{
|
|
11281
|
+
value: "pending",
|
|
11282
|
+
label: "Pending"
|
|
11283
|
+
},
|
|
11284
|
+
{
|
|
11285
|
+
value: "approved",
|
|
11286
|
+
label: "Approved"
|
|
11287
|
+
},
|
|
11288
|
+
{
|
|
11289
|
+
value: "rejected",
|
|
11290
|
+
label: "Rejected"
|
|
11291
|
+
}
|
|
11292
|
+
]
|
|
11037
11293
|
}
|
|
11038
11294
|
],
|
|
11039
11295
|
columns: [
|
|
11296
|
+
{
|
|
11297
|
+
field: "metadata",
|
|
11298
|
+
displayName: "Image",
|
|
11299
|
+
hideInCreate: true,
|
|
11300
|
+
hideInEdit: true,
|
|
11301
|
+
listFilter: false,
|
|
11302
|
+
render: /* @__PURE__ */ __name((_value, item) => renderListThumbnail(productListImageUrl(item)), "render")
|
|
11303
|
+
},
|
|
11040
11304
|
{
|
|
11041
11305
|
field: "name",
|
|
11042
11306
|
displayName: "Name"
|
|
@@ -11098,6 +11362,33 @@ var init_store_crud_configs = __esm({
|
|
|
11098
11362
|
}
|
|
11099
11363
|
]
|
|
11100
11364
|
},
|
|
11365
|
+
{
|
|
11366
|
+
field: "approvalStatus",
|
|
11367
|
+
displayName: "Approval",
|
|
11368
|
+
type: "select",
|
|
11369
|
+
listFilter: false,
|
|
11370
|
+
options: [
|
|
11371
|
+
{
|
|
11372
|
+
value: "pending",
|
|
11373
|
+
label: "Pending"
|
|
11374
|
+
},
|
|
11375
|
+
{
|
|
11376
|
+
value: "approved",
|
|
11377
|
+
label: "Approved"
|
|
11378
|
+
},
|
|
11379
|
+
{
|
|
11380
|
+
value: "rejected",
|
|
11381
|
+
label: "Rejected"
|
|
11382
|
+
}
|
|
11383
|
+
],
|
|
11384
|
+
render: /* @__PURE__ */ __name((value) => {
|
|
11385
|
+
const v = value == null || value === "" ? null : String(value);
|
|
11386
|
+
if (v === "pending") return "Pending";
|
|
11387
|
+
if (v === "approved") return "Approved";
|
|
11388
|
+
if (v === "rejected") return "Rejected";
|
|
11389
|
+
return "\u2014";
|
|
11390
|
+
}, "render")
|
|
11391
|
+
},
|
|
11101
11392
|
{
|
|
11102
11393
|
field: "featured",
|
|
11103
11394
|
displayName: "Featured",
|
|
@@ -11221,6 +11512,14 @@ var init_store_crud_configs = __esm({
|
|
|
11221
11512
|
title: "Collections",
|
|
11222
11513
|
apiEndpoint: "/api/collections",
|
|
11223
11514
|
columns: [
|
|
11515
|
+
{
|
|
11516
|
+
field: "image",
|
|
11517
|
+
displayName: "Image",
|
|
11518
|
+
hideInCreate: true,
|
|
11519
|
+
hideInEdit: true,
|
|
11520
|
+
listFilter: false,
|
|
11521
|
+
render: /* @__PURE__ */ __name((value) => renderListThumbnail(typeof value === "string" ? value : ""), "render")
|
|
11522
|
+
},
|
|
11224
11523
|
{
|
|
11225
11524
|
field: "name",
|
|
11226
11525
|
displayName: "Name"
|
|
@@ -11617,6 +11916,13 @@ var init_store_crud_configs = __esm({
|
|
|
11617
11916
|
field: "slug",
|
|
11618
11917
|
displayName: "Slug"
|
|
11619
11918
|
},
|
|
11919
|
+
{
|
|
11920
|
+
field: "isCatalog",
|
|
11921
|
+
displayName: "Catalog",
|
|
11922
|
+
type: "boolean",
|
|
11923
|
+
hideInCreate: true,
|
|
11924
|
+
hideInEdit: true
|
|
11925
|
+
},
|
|
11620
11926
|
{
|
|
11621
11927
|
field: "active",
|
|
11622
11928
|
displayName: "Active",
|
|
@@ -11919,6 +12225,29 @@ var init_store_crud_configs = __esm({
|
|
|
11919
12225
|
label: "Paid"
|
|
11920
12226
|
}
|
|
11921
12227
|
]
|
|
12228
|
+
},
|
|
12229
|
+
{
|
|
12230
|
+
param: "approvalStatus",
|
|
12231
|
+
label: "Approval",
|
|
12232
|
+
type: "select",
|
|
12233
|
+
options: [
|
|
12234
|
+
{
|
|
12235
|
+
value: "",
|
|
12236
|
+
label: "All"
|
|
12237
|
+
},
|
|
12238
|
+
{
|
|
12239
|
+
value: "pending",
|
|
12240
|
+
label: "Pending"
|
|
12241
|
+
},
|
|
12242
|
+
{
|
|
12243
|
+
value: "approved",
|
|
12244
|
+
label: "Approved"
|
|
12245
|
+
},
|
|
12246
|
+
{
|
|
12247
|
+
value: "rejected",
|
|
12248
|
+
label: "Rejected"
|
|
12249
|
+
}
|
|
12250
|
+
]
|
|
11922
12251
|
}
|
|
11923
12252
|
],
|
|
11924
12253
|
columns: [
|
|
@@ -11950,6 +12279,33 @@ var init_store_crud_configs = __esm({
|
|
|
11950
12279
|
displayName: "Active",
|
|
11951
12280
|
type: "boolean"
|
|
11952
12281
|
},
|
|
12282
|
+
{
|
|
12283
|
+
field: "approvalStatus",
|
|
12284
|
+
displayName: "Approval",
|
|
12285
|
+
type: "select",
|
|
12286
|
+
listFilter: false,
|
|
12287
|
+
options: [
|
|
12288
|
+
{
|
|
12289
|
+
value: "pending",
|
|
12290
|
+
label: "Pending"
|
|
12291
|
+
},
|
|
12292
|
+
{
|
|
12293
|
+
value: "approved",
|
|
12294
|
+
label: "Approved"
|
|
12295
|
+
},
|
|
12296
|
+
{
|
|
12297
|
+
value: "rejected",
|
|
12298
|
+
label: "Rejected"
|
|
12299
|
+
}
|
|
12300
|
+
],
|
|
12301
|
+
render: /* @__PURE__ */ __name((value) => {
|
|
12302
|
+
const v = value == null || value === "" ? null : String(value);
|
|
12303
|
+
if (v === "pending") return "Pending";
|
|
12304
|
+
if (v === "approved") return "Approved";
|
|
12305
|
+
if (v === "rejected") return "Rejected";
|
|
12306
|
+
return "\u2014";
|
|
12307
|
+
}, "render")
|
|
12308
|
+
},
|
|
11953
12309
|
{
|
|
11954
12310
|
field: "comingSoon",
|
|
11955
12311
|
displayName: "Coming soon",
|
|
@@ -12236,7 +12592,12 @@ function SettingsPage() {
|
|
|
12236
12592
|
const [themeSettingsLoading, setThemeSettingsLoading] = useState(true);
|
|
12237
12593
|
const [storeEnabled, setStoreEnabled] = useState(false);
|
|
12238
12594
|
const [multiVendorEnabled, setMultiVendorEnabled] = useState(true);
|
|
12595
|
+
const [vendorCanCreateCategories, setVendorCanCreateCategories] = useState(false);
|
|
12596
|
+
const [vendorCanCreateCollections, setVendorCanCreateCollections] = useState(false);
|
|
12597
|
+
const [vendorCanCreateBrands, setVendorCanCreateBrands] = useState(false);
|
|
12598
|
+
const [requireProductApproval, setRequireProductApproval] = useState(false);
|
|
12239
12599
|
const [eventsEnabled, setEventsEnabled] = useState(true);
|
|
12600
|
+
const [requireEventApproval, setRequireEventApproval] = useState(false);
|
|
12240
12601
|
const [storeSettingsLoading, setStoreSettingsLoading] = useState(true);
|
|
12241
12602
|
const [currency, setCurrency] = useState(DEFAULT_CURRENCY);
|
|
12242
12603
|
const [currencies, setCurrencies] = useState([]);
|
|
@@ -12296,10 +12657,15 @@ function SettingsPage() {
|
|
|
12296
12657
|
}).finally(() => setStoreSettingsLoading(false));
|
|
12297
12658
|
fetch("/api/settings/multi_vendor").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
12298
12659
|
setMultiVendorEnabled(data.enabled !== "false");
|
|
12660
|
+
setVendorCanCreateCategories(data.vendorCanCreateCategories === "true");
|
|
12661
|
+
setVendorCanCreateCollections(data.vendorCanCreateCollections === "true");
|
|
12662
|
+
setVendorCanCreateBrands(data.vendorCanCreateBrands === "true");
|
|
12663
|
+
setRequireProductApproval(data.requireProductApproval === "true");
|
|
12299
12664
|
}).catch(() => {
|
|
12300
12665
|
});
|
|
12301
12666
|
fetch("/api/settings/events").then((r) => r.ok ? r.json() : {}).then((data) => {
|
|
12302
12667
|
setEventsEnabled(data.enabled !== "false");
|
|
12668
|
+
setRequireEventApproval(data.requireEventApproval === "true");
|
|
12303
12669
|
}).catch(() => {
|
|
12304
12670
|
});
|
|
12305
12671
|
fetch("/api/currencies/exchange-rates").then((r) => r.ok ? r.json() : []).then((data) => {
|
|
@@ -12427,6 +12793,22 @@ function SettingsPage() {
|
|
|
12427
12793
|
enabled: {
|
|
12428
12794
|
value: multiVendorEnabled ? "true" : "false",
|
|
12429
12795
|
type: "public"
|
|
12796
|
+
},
|
|
12797
|
+
vendorCanCreateCategories: {
|
|
12798
|
+
value: vendorCanCreateCategories ? "true" : "false",
|
|
12799
|
+
type: "public"
|
|
12800
|
+
},
|
|
12801
|
+
vendorCanCreateCollections: {
|
|
12802
|
+
value: vendorCanCreateCollections ? "true" : "false",
|
|
12803
|
+
type: "public"
|
|
12804
|
+
},
|
|
12805
|
+
vendorCanCreateBrands: {
|
|
12806
|
+
value: vendorCanCreateBrands ? "true" : "false",
|
|
12807
|
+
type: "public"
|
|
12808
|
+
},
|
|
12809
|
+
requireProductApproval: {
|
|
12810
|
+
value: requireProductApproval ? "true" : "false",
|
|
12811
|
+
type: "public"
|
|
12430
12812
|
}
|
|
12431
12813
|
})
|
|
12432
12814
|
});
|
|
@@ -12439,6 +12821,10 @@ function SettingsPage() {
|
|
|
12439
12821
|
enabled: {
|
|
12440
12822
|
value: eventsEnabled ? "true" : "false",
|
|
12441
12823
|
type: "public"
|
|
12824
|
+
},
|
|
12825
|
+
requireEventApproval: {
|
|
12826
|
+
value: requireEventApproval ? "true" : "false",
|
|
12827
|
+
type: "public"
|
|
12442
12828
|
}
|
|
12443
12829
|
})
|
|
12444
12830
|
});
|
|
@@ -12710,8 +13096,46 @@ function SettingsPage() {
|
|
|
12710
13096
|
className: "text-sm font-medium text-gray-700"
|
|
12711
13097
|
}, "Multi Vendor"), /* @__PURE__ */ React.createElement("p", {
|
|
12712
13098
|
className: "text-xs text-gray-500"
|
|
12713
|
-
}, "Enable vendor portals, vendor logins, and vendor-scoped store data. Disabling this blocks vendor-only accounts from signing in."))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
|
|
12714
|
-
className: "mt-4
|
|
13099
|
+
}, "Enable vendor portals, vendor logins, and vendor-scoped store data. Disabling this blocks vendor-only accounts from signing in."))), storeEnabled && multiVendorEnabled && /* @__PURE__ */ React.createElement("div", {
|
|
13100
|
+
className: "mt-4 space-y-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
|
|
13101
|
+
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("p", {
|
|
13102
|
+
className: "text-sm font-medium text-gray-700"
|
|
13103
|
+
}, "Vendor catalog permissions"), /* @__PURE__ */ React.createElement("p", {
|
|
13104
|
+
className: "text-xs text-gray-500 mb-3"
|
|
13105
|
+
}, "When off (default), vendors only pick admin-created categories, collections, and brands on products. When on, vendors also get that Store tab and can create their own.")), /* @__PURE__ */ React.createElement("div", {
|
|
13106
|
+
className: "flex items-center gap-3"
|
|
13107
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
13108
|
+
checked: vendorCanCreateCategories,
|
|
13109
|
+
onCheckedChange: setVendorCanCreateCategories
|
|
13110
|
+
}), /* @__PURE__ */ React.createElement(Label3, {
|
|
13111
|
+
className: "text-sm font-medium text-gray-700"
|
|
13112
|
+
}, "Can vendors create categories")), /* @__PURE__ */ React.createElement("div", {
|
|
13113
|
+
className: "flex items-center gap-3"
|
|
13114
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
13115
|
+
checked: vendorCanCreateCollections,
|
|
13116
|
+
onCheckedChange: setVendorCanCreateCollections
|
|
13117
|
+
}), /* @__PURE__ */ React.createElement(Label3, {
|
|
13118
|
+
className: "text-sm font-medium text-gray-700"
|
|
13119
|
+
}, "Can vendors create collections")), /* @__PURE__ */ React.createElement("div", {
|
|
13120
|
+
className: "flex items-center gap-3"
|
|
13121
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
13122
|
+
checked: vendorCanCreateBrands,
|
|
13123
|
+
onCheckedChange: setVendorCanCreateBrands
|
|
13124
|
+
}), /* @__PURE__ */ React.createElement(Label3, {
|
|
13125
|
+
className: "text-sm font-medium text-gray-700"
|
|
13126
|
+
}, "Can vendors create brands")), /* @__PURE__ */ React.createElement("div", {
|
|
13127
|
+
className: "flex items-start gap-3"
|
|
13128
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
13129
|
+
checked: requireProductApproval,
|
|
13130
|
+
onCheckedChange: setRequireProductApproval
|
|
13131
|
+
}), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
|
|
13132
|
+
className: "text-sm font-medium text-gray-700"
|
|
13133
|
+
}, "Require product approval"), /* @__PURE__ */ React.createElement("p", {
|
|
13134
|
+
className: "text-xs text-gray-500 mt-0.5"
|
|
13135
|
+
}, "When on, new vendor products start as waiting for approval. Admins approve or reject; only after approval can the vendor set the product to available (live).")))), storeEnabled && /* @__PURE__ */ React.createElement("div", {
|
|
13136
|
+
className: "mt-4 space-y-3 p-4 bg-gray-50 rounded-lg border border-gray-200"
|
|
13137
|
+
}, /* @__PURE__ */ React.createElement("div", {
|
|
13138
|
+
className: "flex items-center gap-3"
|
|
12715
13139
|
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
12716
13140
|
checked: eventsEnabled,
|
|
12717
13141
|
onCheckedChange: setEventsEnabled
|
|
@@ -12719,7 +13143,16 @@ function SettingsPage() {
|
|
|
12719
13143
|
className: "text-sm font-medium text-gray-700"
|
|
12720
13144
|
}, "Events"), /* @__PURE__ */ React.createElement("p", {
|
|
12721
13145
|
className: "text-xs text-gray-500"
|
|
12722
|
-
}, "Enable event management. Disabling this hides the Events tab and blocks all event-related APIs."))),
|
|
13146
|
+
}, "Enable event management. Disabling this hides the Events tab and blocks all event-related APIs."))), eventsEnabled && multiVendorEnabled ? /* @__PURE__ */ React.createElement("div", {
|
|
13147
|
+
className: "flex items-start gap-3 pl-1 border-t border-gray-200 pt-3"
|
|
13148
|
+
}, /* @__PURE__ */ React.createElement(Switch, {
|
|
13149
|
+
checked: requireEventApproval,
|
|
13150
|
+
onCheckedChange: setRequireEventApproval
|
|
13151
|
+
}), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Label3, {
|
|
13152
|
+
className: "text-sm font-medium text-gray-700"
|
|
13153
|
+
}, "Require event approval"), /* @__PURE__ */ React.createElement("p", {
|
|
13154
|
+
className: "text-xs text-gray-500 mt-0.5"
|
|
13155
|
+
}, "When on, new vendor events start as pending. Admins approve or reject; approval activates the event (live)."))) : null), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
|
|
12723
13156
|
className: "flex items-center justify-between mb-1"
|
|
12724
13157
|
}, /* @__PURE__ */ React.createElement("label", {
|
|
12725
13158
|
className: "block text-sm font-semibold text-gray-700"
|
|
@@ -13558,7 +13991,11 @@ function ScheduleAuthorSelect({ value, onChange, disabled }) {
|
|
|
13558
13991
|
(async () => {
|
|
13559
13992
|
setLoading(true);
|
|
13560
13993
|
try {
|
|
13561
|
-
const
|
|
13994
|
+
const params = new URLSearchParams({
|
|
13995
|
+
limit: "100",
|
|
13996
|
+
groupName: ADMIN_GROUP_NAME
|
|
13997
|
+
});
|
|
13998
|
+
const res = await fetch(`/api/users?${params}`);
|
|
13562
13999
|
if (!res.ok || cancelled) return;
|
|
13563
14000
|
const data = await res.json();
|
|
13564
14001
|
const rows = Array.isArray(data.data) ? data.data : [];
|
|
@@ -13591,7 +14028,7 @@ function ScheduleAuthorSelect({ value, onChange, disabled }) {
|
|
|
13591
14028
|
}, /* @__PURE__ */ React.createElement(SelectTrigger, {
|
|
13592
14029
|
className: "w-full"
|
|
13593
14030
|
}, /* @__PURE__ */ React.createElement(SelectValue, {
|
|
13594
|
-
placeholder: users.length === 0 ? "No
|
|
14031
|
+
placeholder: users.length === 0 ? "No administrators found" : "Select author"
|
|
13595
14032
|
})), /* @__PURE__ */ React.createElement(SelectContent, {
|
|
13596
14033
|
className: "max-h-72"
|
|
13597
14034
|
}, users.map((u) => /* @__PURE__ */ React.createElement(SelectItem, {
|
|
@@ -13603,6 +14040,7 @@ var init_ScheduleAuthorSelect = __esm({
|
|
|
13603
14040
|
"src/admin/ScheduleAuthorSelect.tsx"() {
|
|
13604
14041
|
"use client";
|
|
13605
14042
|
init_select();
|
|
14043
|
+
init_permission_entities();
|
|
13606
14044
|
__name(userLabel, "userLabel");
|
|
13607
14045
|
__name(ScheduleAuthorSelect, "ScheduleAuthorSelect");
|
|
13608
14046
|
}
|
|
@@ -16989,15 +17427,13 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
16989
17427
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
16990
17428
|
}, "Layout below merges with Branding settings; values here override branding when set. Use absolute URLs for logos in email."), /* @__PURE__ */ React.createElement("div", {
|
|
16991
17429
|
className: "space-y-1"
|
|
16992
|
-
}, /* @__PURE__ */ React.createElement(
|
|
16993
|
-
|
|
16994
|
-
className: "text-sm"
|
|
16995
|
-
}, "Logo URL (optional override)"), /* @__PURE__ */ React.createElement(Input, {
|
|
16996
|
-
id: `${settingsGroup}-logoUrl`,
|
|
17430
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
17431
|
+
label: "Logo (optional override)",
|
|
16997
17432
|
value: logoUrl,
|
|
16998
|
-
onChange:
|
|
17433
|
+
onChange: setLogoUrl,
|
|
17434
|
+
previewVariant: "logo",
|
|
16999
17435
|
placeholder: "https://\u2026",
|
|
17000
|
-
|
|
17436
|
+
inputClassName: "h-8 text-sm w-full rounded-md border border-input bg-background px-3"
|
|
17001
17437
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
17002
17438
|
className: "space-y-1"
|
|
17003
17439
|
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
@@ -17050,22 +17486,23 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17050
17486
|
className: "flex flex-wrap items-end gap-2 border-b border-border/60 pb-3 dark:border-gray-600"
|
|
17051
17487
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
17052
17488
|
className: "min-w-[160px] flex-1 space-y-1"
|
|
17053
|
-
}, /* @__PURE__ */ React.createElement(
|
|
17054
|
-
|
|
17055
|
-
}, "Icon image URL"), /* @__PURE__ */ React.createElement(Input, {
|
|
17489
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
17490
|
+
label: "Icon image",
|
|
17056
17491
|
value: row.iconUrl,
|
|
17057
|
-
onChange: /* @__PURE__ */ __name((
|
|
17492
|
+
onChange: /* @__PURE__ */ __name((v) => {
|
|
17058
17493
|
const next = [
|
|
17059
17494
|
...socialLinkRows
|
|
17060
17495
|
];
|
|
17061
17496
|
next[i] = {
|
|
17062
17497
|
...next[i],
|
|
17063
|
-
iconUrl:
|
|
17498
|
+
iconUrl: v
|
|
17064
17499
|
};
|
|
17065
17500
|
setSocialLinkRows(next);
|
|
17066
17501
|
}, "onChange"),
|
|
17502
|
+
previewVariant: "logo",
|
|
17067
17503
|
placeholder: "https://\u2026",
|
|
17068
|
-
|
|
17504
|
+
inputClassName: "h-8 text-sm w-full rounded-md border border-input bg-background px-3",
|
|
17505
|
+
labelClassName: "text-xs text-muted-foreground"
|
|
17069
17506
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
17070
17507
|
className: "min-w-[160px] flex-1 space-y-1"
|
|
17071
17508
|
}, /* @__PURE__ */ React.createElement(Label3, {
|
|
@@ -17712,15 +18149,13 @@ function PluginSettingsPanel({ descriptor, onSaved }) {
|
|
|
17712
18149
|
className: "h-8 text-sm"
|
|
17713
18150
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
17714
18151
|
className: "space-y-1"
|
|
17715
|
-
}, /* @__PURE__ */ React.createElement(
|
|
17716
|
-
|
|
17717
|
-
className: "text-sm"
|
|
17718
|
-
}, "Icon image URL"), /* @__PURE__ */ React.createElement(Input, {
|
|
17719
|
-
id: `${settingsGroup}-iconImageUrl`,
|
|
18152
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
18153
|
+
label: "Icon image",
|
|
17720
18154
|
value: iconImageUrl,
|
|
17721
|
-
onChange:
|
|
18155
|
+
onChange: setIconImageUrl,
|
|
18156
|
+
previewVariant: "logo",
|
|
17722
18157
|
placeholder: "https://\u2026 or /images/chat-icon.png",
|
|
17723
|
-
|
|
18158
|
+
inputClassName: "h-8 text-sm w-full rounded-md border border-input bg-background px-3"
|
|
17724
18159
|
}), /* @__PURE__ */ React.createElement("p", {
|
|
17725
18160
|
className: "text-xs text-gray-500 dark:text-gray-400"
|
|
17726
18161
|
}, "PNG or image URL. Leave empty to use emoji below.")), /* @__PURE__ */ React.createElement("div", {
|
|
@@ -18280,6 +18715,7 @@ var init_PluginsPage = __esm({
|
|
|
18280
18715
|
init_checkbox();
|
|
18281
18716
|
init_select();
|
|
18282
18717
|
init_EventNotificationsPluginSettings();
|
|
18718
|
+
init_ImageOrUrlField();
|
|
18283
18719
|
init_chat_email_intent();
|
|
18284
18720
|
init_llm_agent_scope();
|
|
18285
18721
|
__name(normalizeLinkedInOrganizations, "normalizeLinkedInOrganizations");
|
|
@@ -19963,7 +20399,7 @@ var init_VendorPortalProfilePage = __esm({
|
|
|
19963
20399
|
__name(VendorPortalProfilePage, "VendorPortalProfilePage");
|
|
19964
20400
|
}
|
|
19965
20401
|
});
|
|
19966
|
-
function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", closeHref, onClose, menuItems = [] }) {
|
|
20402
|
+
function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", closeHref, onClose, headerExtra, menuItems = [] }) {
|
|
19967
20403
|
const router = useRouter();
|
|
19968
20404
|
const handleClose = /* @__PURE__ */ __name(() => {
|
|
19969
20405
|
if (onClose) onClose();
|
|
@@ -19987,7 +20423,7 @@ function DetailPageHeader({ title, subtitle, backHref, backLabel = "Back", close
|
|
|
19987
20423
|
className: "text-sm text-gray-400 truncate"
|
|
19988
20424
|
}, subtitle))), /* @__PURE__ */ React.createElement("div", {
|
|
19989
20425
|
className: "flex items-center gap-2 shrink-0"
|
|
19990
|
-
}, menuItems.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
20426
|
+
}, headerExtra, menuItems.length > 0 && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", {
|
|
19991
20427
|
className: "flex items-center gap-2 md:hidden"
|
|
19992
20428
|
}, menuItems.map((item, i) => {
|
|
19993
20429
|
const Icon2 = item.icon;
|
|
@@ -25167,15 +25603,11 @@ function SeoTabContent(props) {
|
|
|
25167
25603
|
onChange: /* @__PURE__ */ __name((e) => props.setSeoOgDescription(e.target.value), "onChange"),
|
|
25168
25604
|
placeholder: "Open Graph description",
|
|
25169
25605
|
rows: 2
|
|
25170
|
-
})), /* @__PURE__ */ React26__default.createElement(
|
|
25171
|
-
|
|
25172
|
-
}, /* @__PURE__ */ React26__default.createElement(Label3, {
|
|
25173
|
-
className: "text-xs"
|
|
25174
|
-
}, "OG Image"), /* @__PURE__ */ React26__default.createElement(Input, {
|
|
25606
|
+
})), /* @__PURE__ */ React26__default.createElement(ImageOrUrlField, {
|
|
25607
|
+
label: "OG Image",
|
|
25175
25608
|
value: props.seoOgImage,
|
|
25176
|
-
onChange:
|
|
25177
|
-
|
|
25178
|
-
})));
|
|
25609
|
+
onChange: props.setSeoOgImage
|
|
25610
|
+
}));
|
|
25179
25611
|
}
|
|
25180
25612
|
function CollapsibleSection({ title, icon: Icon2, open, onToggle, children }) {
|
|
25181
25613
|
return /* @__PURE__ */ React26__default.createElement("div", {
|
|
@@ -25561,6 +25993,7 @@ var init_PageBuilderPage = __esm({
|
|
|
25561
25993
|
init_ComponentSettings();
|
|
25562
25994
|
init_admin_config_context();
|
|
25563
25995
|
init_registry();
|
|
25996
|
+
init_ImageOrUrlField();
|
|
25564
25997
|
__name(createSelectable, "createSelectable");
|
|
25565
25998
|
__name(buildEditorResolver, "buildEditorResolver");
|
|
25566
25999
|
__name(getIcon, "getIcon");
|
|
@@ -25623,15 +26056,12 @@ function SeoSection({ values, onChange }) {
|
|
|
25623
26056
|
onChange: /* @__PURE__ */ __name((e) => onChange("seoOgDescription", e.target.value), "onChange"),
|
|
25624
26057
|
className: textareaCls,
|
|
25625
26058
|
rows: 2
|
|
25626
|
-
})), /* @__PURE__ */ React.createElement(
|
|
25627
|
-
|
|
25628
|
-
}, "OG Image"), /* @__PURE__ */ React.createElement("input", {
|
|
25629
|
-
type: "url",
|
|
26059
|
+
})), /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
26060
|
+
label: "OG Image",
|
|
25630
26061
|
value: values.seoOgImage,
|
|
25631
|
-
onChange: /* @__PURE__ */ __name((
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
}))));
|
|
26062
|
+
onChange: /* @__PURE__ */ __name((v) => onChange("seoOgImage", v), "onChange"),
|
|
26063
|
+
inputClassName: inputCls9
|
|
26064
|
+
})));
|
|
25635
26065
|
}
|
|
25636
26066
|
async function saveSeo(seo, slug, existingSeoId) {
|
|
25637
26067
|
const hasSeo = seo.seoTitle || seo.seoDescription || seo.seoKeywords || seo.seoOgTitle || seo.seoOgDescription || seo.seoOgImage;
|
|
@@ -25696,6 +26126,7 @@ async function fetchSeo(seoId) {
|
|
|
25696
26126
|
var init_SeoSection = __esm({
|
|
25697
26127
|
"src/components/Admin/SeoSection.tsx"() {
|
|
25698
26128
|
"use client";
|
|
26129
|
+
init_ImageOrUrlField();
|
|
25699
26130
|
__name(SeoSection, "SeoSection");
|
|
25700
26131
|
__name(saveSeo, "saveSeo");
|
|
25701
26132
|
__name(fetchSeo, "fetchSeo");
|
|
@@ -25710,6 +26141,8 @@ __export(BrandEditPage_exports, {
|
|
|
25710
26141
|
function BrandEditPage({ brandId }) {
|
|
25711
26142
|
const router = useRouter();
|
|
25712
26143
|
const searchParams = useSearchParams();
|
|
26144
|
+
const { data: session } = useSession();
|
|
26145
|
+
const vendorPortal = isVendorPortalUser(session?.user);
|
|
25713
26146
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/brands";
|
|
25714
26147
|
const create = isCreate(brandId);
|
|
25715
26148
|
const dupParam = searchParams.get("duplicateFrom");
|
|
@@ -25811,6 +26244,9 @@ function BrandEditPage({ brandId }) {
|
|
|
25811
26244
|
active,
|
|
25812
26245
|
sortOrder
|
|
25813
26246
|
};
|
|
26247
|
+
if (!vendorPortal) {
|
|
26248
|
+
payload.isCatalog = true;
|
|
26249
|
+
}
|
|
25814
26250
|
if (savedSeoId) payload.seoId = savedSeoId;
|
|
25815
26251
|
const res = await fetch(create ? "/api/brands" : `/api/brands/${brandId}`, {
|
|
25816
26252
|
method: create ? "POST" : "PUT",
|
|
@@ -25902,13 +26338,12 @@ function BrandEditPage({ brandId }) {
|
|
|
25902
26338
|
onChange: /* @__PURE__ */ __name((e) => setDescription(e.target.value), "onChange"),
|
|
25903
26339
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm min-h-[80px]",
|
|
25904
26340
|
rows: 3
|
|
25905
|
-
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
25906
|
-
|
|
25907
|
-
}, "Logo URL"), /* @__PURE__ */ React.createElement("input", {
|
|
25908
|
-
type: "url",
|
|
26341
|
+
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
26342
|
+
label: "Logo",
|
|
25909
26343
|
value: logo,
|
|
25910
|
-
onChange:
|
|
25911
|
-
|
|
26344
|
+
onChange: setLogo,
|
|
26345
|
+
previewVariant: "logo",
|
|
26346
|
+
inputClassName: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm"
|
|
25912
26347
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
25913
26348
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
25914
26349
|
}, "Sort order"), /* @__PURE__ */ React.createElement("input", {
|
|
@@ -25951,6 +26386,8 @@ var init_BrandEditPage = __esm({
|
|
|
25951
26386
|
init_SeoSection();
|
|
25952
26387
|
init_DetailPageLayout();
|
|
25953
26388
|
init_DetailPageHeader();
|
|
26389
|
+
init_vendor_scope();
|
|
26390
|
+
init_ImageOrUrlField();
|
|
25954
26391
|
isCreate = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
25955
26392
|
__name(BrandEditPage, "BrandEditPage");
|
|
25956
26393
|
}
|
|
@@ -26858,16 +27295,38 @@ function ProductVariantsSection({ hasVariants, onHasVariantsChange, variantOptio
|
|
|
26858
27295
|
}, "Reserved"), /* @__PURE__ */ React.createElement("option", {
|
|
26859
27296
|
value: "sold"
|
|
26860
27297
|
}, "Sold"))), /* @__PURE__ */ React.createElement("td", {
|
|
26861
|
-
className: "px-3 py-2 align-top"
|
|
26862
|
-
},
|
|
26863
|
-
|
|
26864
|
-
|
|
26865
|
-
|
|
26866
|
-
|
|
26867
|
-
|
|
26868
|
-
|
|
26869
|
-
|
|
26870
|
-
|
|
27298
|
+
className: "px-3 py-2 align-top min-w-[240px]"
|
|
27299
|
+
}, (() => {
|
|
27300
|
+
const lines = row.imageUrlsText === "" ? [
|
|
27301
|
+
""
|
|
27302
|
+
] : row.imageUrlsText.split("\n");
|
|
27303
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
27304
|
+
className: "space-y-2"
|
|
27305
|
+
}, lines.map((url, ui) => /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
27306
|
+
key: ui,
|
|
27307
|
+
label: ui === 0 ? "Images" : `Image ${ui + 1}`,
|
|
27308
|
+
value: url,
|
|
27309
|
+
onChange: /* @__PURE__ */ __name((v) => {
|
|
27310
|
+
const next = [
|
|
27311
|
+
...lines
|
|
27312
|
+
];
|
|
27313
|
+
next[ui] = v;
|
|
27314
|
+
setVariantField(i, "imageUrlsText", next.join("\n"));
|
|
27315
|
+
}, "onChange"),
|
|
27316
|
+
inputClassName: inputCls2
|
|
27317
|
+
})), /* @__PURE__ */ React.createElement("button", {
|
|
27318
|
+
type: "button",
|
|
27319
|
+
onClick: /* @__PURE__ */ __name(() => setVariantField(i, "imageUrlsText", [
|
|
27320
|
+
...lines,
|
|
27321
|
+
""
|
|
27322
|
+
].join("\n")), "onClick"),
|
|
27323
|
+
className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-[11px] text-gray-700 hover:bg-gray-50"
|
|
27324
|
+
}, /* @__PURE__ */ React.createElement(Plus, {
|
|
27325
|
+
className: "h-3 w-3"
|
|
27326
|
+
}), " Add image"), /* @__PURE__ */ React.createElement("p", {
|
|
27327
|
+
className: "text-[11px] text-gray-500"
|
|
27328
|
+
}, "First image is used on PDP."));
|
|
27329
|
+
})()), /* @__PURE__ */ React.createElement("td", {
|
|
26871
27330
|
className: "px-3 py-2 align-top text-right"
|
|
26872
27331
|
}, /* @__PURE__ */ React.createElement("button", {
|
|
26873
27332
|
type: "button",
|
|
@@ -26882,6 +27341,7 @@ var init_ProductVariantsSection = __esm({
|
|
|
26882
27341
|
"src/admin/pages/ProductVariantsSection.tsx"() {
|
|
26883
27342
|
"use client";
|
|
26884
27343
|
init_product_variants();
|
|
27344
|
+
init_ImageOrUrlField();
|
|
26885
27345
|
labelCls2 = "block text-xs font-medium text-gray-600 mb-1";
|
|
26886
27346
|
inputCls2 = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm";
|
|
26887
27347
|
sectionCls2 = "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50";
|
|
@@ -27077,13 +27537,16 @@ function ProductEditPage({ productId }) {
|
|
|
27077
27537
|
const router = useRouter();
|
|
27078
27538
|
const searchParams = useSearchParams();
|
|
27079
27539
|
const { data: session } = useSession();
|
|
27540
|
+
const { eventsEnabled, requireProductApproval } = useContext(AdminConfigContext);
|
|
27541
|
+
const eventsOn = eventsEnabled !== false;
|
|
27542
|
+
const approvalOn = requireProductApproval === true;
|
|
27080
27543
|
const vendorPortal = isVendorPortalUser(session?.user);
|
|
27081
27544
|
const categoryIdParam = searchParams.get("categoryId")?.trim() ?? "";
|
|
27082
27545
|
const collectionIdParam = searchParams.get("collectionId")?.trim() ?? "";
|
|
27083
27546
|
const eventIdParam = searchParams.get("eventId")?.trim() ?? "";
|
|
27084
27547
|
const lockCategoryFromStore = isCreate2(productId) && /^\d+$/.test(categoryIdParam);
|
|
27085
27548
|
const lockCollectionFromQuery = isCreate2(productId) && /^\d+$/.test(collectionIdParam);
|
|
27086
|
-
const lockEventFromQuery = isCreate2(productId) && /^\d+$/.test(eventIdParam);
|
|
27549
|
+
const lockEventFromQuery = eventsOn && isCreate2(productId) && /^\d+$/.test(eventIdParam);
|
|
27087
27550
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? (lockCategoryFromStore ? `/admin/products?categoryId=${categoryIdParam}` : "/admin/products");
|
|
27088
27551
|
const create = isCreate2(productId);
|
|
27089
27552
|
const dupParam = searchParams.get("duplicateFrom");
|
|
@@ -27114,6 +27577,11 @@ function ProductEditPage({ productId }) {
|
|
|
27114
27577
|
const [compareAtPrice, setCompareAtPrice] = useState(0);
|
|
27115
27578
|
const [quantity, setQuantity] = useState(1);
|
|
27116
27579
|
const [status, setStatus] = useState("draft");
|
|
27580
|
+
const [approvalStatus, setApprovalStatus] = useState("pending");
|
|
27581
|
+
const [rejectionReason, setRejectionReason] = useState("");
|
|
27582
|
+
const [rejectModalOpen, setRejectModalOpen] = useState(false);
|
|
27583
|
+
const [rejectDraft, setRejectDraft] = useState("");
|
|
27584
|
+
const approvalBeforeRejectRef = useRef("pending");
|
|
27117
27585
|
const [featured, setFeatured] = useState(false);
|
|
27118
27586
|
const [description, setDescription] = useState("");
|
|
27119
27587
|
const [images, setImages] = useState([
|
|
@@ -27218,7 +27686,7 @@ function ProductEditPage({ productId }) {
|
|
|
27218
27686
|
try {
|
|
27219
27687
|
const [brandRes, catRes, attrRes, taxesRes, eventsRes, formsRes, refundRes] = await Promise.all([
|
|
27220
27688
|
fetch("/api/brands?limit=500"),
|
|
27221
|
-
fetch("/api/product_categories?limit=500&isCatalog=true"),
|
|
27689
|
+
fetch(vendorPortal ? "/api/product_categories?limit=500" : "/api/product_categories?limit=500&isCatalog=true"),
|
|
27222
27690
|
fetch("/api/attributes?limit=500"),
|
|
27223
27691
|
fetch("/api/taxes?limit=200&sortField=name&sortOrder=asc"),
|
|
27224
27692
|
fetch("/api/events?limit=200&sortField=startDate&sortOrder=desc"),
|
|
@@ -27331,6 +27799,8 @@ function ProductEditPage({ productId }) {
|
|
|
27331
27799
|
setCompareAtPrice(Number.isFinite(rawCompare) ? rawCompare : 0);
|
|
27332
27800
|
setQuantity(product.quantity ?? 1);
|
|
27333
27801
|
setStatus(product.status ?? "draft");
|
|
27802
|
+
setApprovalStatus(typeof product.approvalStatus === "string" && product.approvalStatus ? product.approvalStatus : "pending");
|
|
27803
|
+
setRejectionReason(typeof product.rejectionReason === "string" ? product.rejectionReason : "");
|
|
27334
27804
|
setFeatured(product.featured ?? false);
|
|
27335
27805
|
setDescription((m && typeof m.description === "string" ? m.description : "") ?? "");
|
|
27336
27806
|
const rawImages = m?.images;
|
|
@@ -27466,6 +27936,16 @@ function ProductEditPage({ productId }) {
|
|
|
27466
27936
|
create,
|
|
27467
27937
|
eventId
|
|
27468
27938
|
]);
|
|
27939
|
+
useEffect(() => {
|
|
27940
|
+
if (create && vendorPortal && approvalOn) {
|
|
27941
|
+
setApprovalStatus("pending");
|
|
27942
|
+
setStatus((s) => s === "available" ? "draft" : s);
|
|
27943
|
+
}
|
|
27944
|
+
}, [
|
|
27945
|
+
create,
|
|
27946
|
+
vendorPortal,
|
|
27947
|
+
approvalOn
|
|
27948
|
+
]);
|
|
27469
27949
|
useEffect(() => {
|
|
27470
27950
|
if (!create || !name.trim()) return;
|
|
27471
27951
|
setProductSlug(slugifyProductName(name));
|
|
@@ -27500,6 +27980,33 @@ function ProductEditPage({ productId }) {
|
|
|
27500
27980
|
}
|
|
27501
27981
|
setter(num);
|
|
27502
27982
|
}, "handleNumberChange");
|
|
27983
|
+
const openRejectModal = /* @__PURE__ */ __name((fromStatus) => {
|
|
27984
|
+
approvalBeforeRejectRef.current = fromStatus === "rejected" ? "pending" : fromStatus;
|
|
27985
|
+
setRejectDraft(rejectionReason);
|
|
27986
|
+
setApprovalStatus("rejected");
|
|
27987
|
+
setRejectModalOpen(true);
|
|
27988
|
+
}, "openRejectModal");
|
|
27989
|
+
const confirmRejectReason = /* @__PURE__ */ __name(() => {
|
|
27990
|
+
const reason = rejectDraft.trim();
|
|
27991
|
+
if (!reason) return;
|
|
27992
|
+
setRejectionReason(reason);
|
|
27993
|
+
setRejectModalOpen(false);
|
|
27994
|
+
}, "confirmRejectReason");
|
|
27995
|
+
const cancelRejectModal = /* @__PURE__ */ __name(() => {
|
|
27996
|
+
if (!rejectionReason.trim()) {
|
|
27997
|
+
setApprovalStatus(approvalBeforeRejectRef.current || "pending");
|
|
27998
|
+
}
|
|
27999
|
+
setRejectDraft(rejectionReason);
|
|
28000
|
+
setRejectModalOpen(false);
|
|
28001
|
+
}, "cancelRejectModal");
|
|
28002
|
+
const handleApprovalSelect = /* @__PURE__ */ __name((value) => {
|
|
28003
|
+
if (value === "rejected") {
|
|
28004
|
+
openRejectModal(approvalStatus);
|
|
28005
|
+
return;
|
|
28006
|
+
}
|
|
28007
|
+
setApprovalStatus(value);
|
|
28008
|
+
if (value !== "rejected") setRejectionReason("");
|
|
28009
|
+
}, "handleApprovalSelect");
|
|
27503
28010
|
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
27504
28011
|
setErrors([]);
|
|
27505
28012
|
if (!name.trim()) {
|
|
@@ -27508,6 +28015,14 @@ function ProductEditPage({ productId }) {
|
|
|
27508
28015
|
]);
|
|
27509
28016
|
return;
|
|
27510
28017
|
}
|
|
28018
|
+
if (approvalOn && !vendorPortal && approvalStatus === "rejected" && !rejectionReason.trim()) {
|
|
28019
|
+
setRejectDraft("");
|
|
28020
|
+
setRejectModalOpen(true);
|
|
28021
|
+
setErrors([
|
|
28022
|
+
"Rejection reason is required"
|
|
28023
|
+
]);
|
|
28024
|
+
return;
|
|
28025
|
+
}
|
|
27511
28026
|
if (!defaultPriceStr.trim()) {
|
|
27512
28027
|
setErrors([
|
|
27513
28028
|
`${pricingConfig.defaultCurrency} price is required`
|
|
@@ -27570,11 +28085,21 @@ function ProductEditPage({ productId }) {
|
|
|
27570
28085
|
currencyPrices: null,
|
|
27571
28086
|
compareAtPrice: compareAtPriceValue,
|
|
27572
28087
|
quantity: resolvedQuantity,
|
|
27573
|
-
status,
|
|
28088
|
+
status: create && vendorPortal && approvalOn && status === "available" ? "draft" : status,
|
|
27574
28089
|
featured,
|
|
27575
28090
|
contactFormId,
|
|
27576
28091
|
metadata
|
|
27577
28092
|
};
|
|
28093
|
+
if (approvalOn) {
|
|
28094
|
+
if (vendorPortal && create) {
|
|
28095
|
+
productPayload.approvalStatus = "pending";
|
|
28096
|
+
} else if (!vendorPortal) {
|
|
28097
|
+
productPayload.approvalStatus = approvalStatus;
|
|
28098
|
+
if (approvalStatus === "rejected") {
|
|
28099
|
+
productPayload.rejectionReason = rejectionReason.trim();
|
|
28100
|
+
}
|
|
28101
|
+
}
|
|
28102
|
+
}
|
|
27578
28103
|
const res = await fetch(create ? "/api/products" : `/api/products/${productId}`, {
|
|
27579
28104
|
method: create ? "POST" : "PUT",
|
|
27580
28105
|
headers: {
|
|
@@ -27596,6 +28121,15 @@ function ProductEditPage({ productId }) {
|
|
|
27596
28121
|
if (typeof savedProduct.slug === "string") {
|
|
27597
28122
|
setProductSlug(savedProduct.slug);
|
|
27598
28123
|
}
|
|
28124
|
+
if (typeof savedProduct.status === "string") {
|
|
28125
|
+
setStatus(savedProduct.status);
|
|
28126
|
+
}
|
|
28127
|
+
if (typeof savedProduct.approvalStatus === "string") {
|
|
28128
|
+
setApprovalStatus(savedProduct.approvalStatus);
|
|
28129
|
+
}
|
|
28130
|
+
if (approvalStatus === "approved") {
|
|
28131
|
+
setRejectionReason("");
|
|
28132
|
+
}
|
|
27599
28133
|
const savedId = create ? savedProduct.id : productId;
|
|
27600
28134
|
const savedSeoId = await saveSeo(seo, productSlugValue, seoId);
|
|
27601
28135
|
const linkedSeoId = savedSeoId ?? savedProduct.seoId ?? null;
|
|
@@ -27796,7 +28330,7 @@ function ProductEditPage({ productId }) {
|
|
|
27796
28330
|
}
|
|
27797
28331
|
setVariantRows([]);
|
|
27798
28332
|
}
|
|
27799
|
-
if (create && eventId != null) {
|
|
28333
|
+
if (create && eventsOn && eventId != null) {
|
|
27800
28334
|
const attachRes = await fetch("/api/event_products", {
|
|
27801
28335
|
method: "POST",
|
|
27802
28336
|
headers: {
|
|
@@ -27901,6 +28435,27 @@ function ProductEditPage({ productId }) {
|
|
|
27901
28435
|
title: pageTitle,
|
|
27902
28436
|
subtitle: pageSubtitle,
|
|
27903
28437
|
closeHref: listReturnUrl,
|
|
28438
|
+
headerExtra: approvalOn && !vendorPortal ? /* @__PURE__ */ React.createElement("div", {
|
|
28439
|
+
className: "flex items-center gap-2"
|
|
28440
|
+
}, /* @__PURE__ */ React.createElement("select", {
|
|
28441
|
+
value: approvalStatus,
|
|
28442
|
+
onChange: /* @__PURE__ */ __name((e) => handleApprovalSelect(e.target.value), "onChange"),
|
|
28443
|
+
className: "h-8 rounded-md border border-gray-600 bg-gray-900 text-white text-xs px-2 max-w-[10rem]",
|
|
28444
|
+
"aria-label": "Approval status"
|
|
28445
|
+
}, /* @__PURE__ */ React.createElement("option", {
|
|
28446
|
+
value: "pending"
|
|
28447
|
+
}, "Pending"), /* @__PURE__ */ React.createElement("option", {
|
|
28448
|
+
value: "approved"
|
|
28449
|
+
}, "Approve"), /* @__PURE__ */ React.createElement("option", {
|
|
28450
|
+
value: "rejected"
|
|
28451
|
+
}, "Reject")), approvalStatus === "rejected" ? /* @__PURE__ */ React.createElement("button", {
|
|
28452
|
+
type: "button",
|
|
28453
|
+
onClick: /* @__PURE__ */ __name(() => openRejectModal("rejected"), "onClick"),
|
|
28454
|
+
className: "text-xs text-amber-300 hover:text-amber-200 underline underline-offset-2 max-w-[9rem] truncate",
|
|
28455
|
+
title: rejectionReason || "Add rejection reason"
|
|
28456
|
+
}, rejectionReason.trim() ? "Edit reason" : "Add reason") : null) : approvalOn && vendorPortal ? /* @__PURE__ */ React.createElement("span", {
|
|
28457
|
+
className: "text-xs text-gray-300 capitalize hidden sm:inline"
|
|
28458
|
+
}, approvalStatus.replace(/_/g, " ")) : null,
|
|
27904
28459
|
menuItems: [
|
|
27905
28460
|
{
|
|
27906
28461
|
label: saving ? "Saving..." : "Save",
|
|
@@ -27913,7 +28468,31 @@ function ProductEditPage({ productId }) {
|
|
|
27913
28468
|
onClick: /* @__PURE__ */ __name(() => setFeatured(!featured), "onClick")
|
|
27914
28469
|
}
|
|
27915
28470
|
]
|
|
27916
|
-
}),
|
|
28471
|
+
}), /* @__PURE__ */ React.createElement(Dialog, {
|
|
28472
|
+
open: rejectModalOpen,
|
|
28473
|
+
onOpenChange: /* @__PURE__ */ __name((open) => {
|
|
28474
|
+
if (!open) cancelRejectModal();
|
|
28475
|
+
}, "onOpenChange")
|
|
28476
|
+
}, /* @__PURE__ */ React.createElement(DialogContent, {
|
|
28477
|
+
className: "max-w-md"
|
|
28478
|
+
}, /* @__PURE__ */ React.createElement(DialogHeader, null, /* @__PURE__ */ React.createElement(DialogTitle, null, "Rejection reason"), /* @__PURE__ */ React.createElement(DialogDescription, null, "Explain what the vendor needs to fix. This is required before you can save a rejected product.")), /* @__PURE__ */ React.createElement("textarea", {
|
|
28479
|
+
value: rejectDraft,
|
|
28480
|
+
onChange: /* @__PURE__ */ __name((e) => setRejectDraft(e.target.value), "onChange"),
|
|
28481
|
+
className: "w-full min-h-[100px] rounded-md border border-gray-300 px-3 py-2 text-sm",
|
|
28482
|
+
placeholder: "Explain what needs to change\u2026",
|
|
28483
|
+
autoFocus: true
|
|
28484
|
+
}), /* @__PURE__ */ React.createElement(DialogFooter, {
|
|
28485
|
+
className: "gap-2 sm:gap-0"
|
|
28486
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
28487
|
+
type: "button",
|
|
28488
|
+
variant: "outline",
|
|
28489
|
+
onClick: cancelRejectModal
|
|
28490
|
+
}, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
|
|
28491
|
+
type: "button",
|
|
28492
|
+
variant: "destructive",
|
|
28493
|
+
disabled: !rejectDraft.trim(),
|
|
28494
|
+
onClick: confirmRejectReason
|
|
28495
|
+
}, "Confirm reject")))), errors.length > 0 && /* @__PURE__ */ React.createElement("div", {
|
|
27917
28496
|
className: "bg-red-50 border-l-4 border-red-400 p-4 mx-6 mt-4"
|
|
27918
28497
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
27919
28498
|
className: "flex"
|
|
@@ -28036,7 +28615,7 @@ function ProductEditPage({ productId }) {
|
|
|
28036
28615
|
className: "mt-1 text-xs text-gray-500"
|
|
28037
28616
|
}, "Only collections in the selected category are listed.") : /* @__PURE__ */ React.createElement("p", {
|
|
28038
28617
|
className: "mt-1 text-xs text-gray-500"
|
|
28039
|
-
}, "Select a category to load collections.")), create ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
28618
|
+
}, "Select a category to load collections.")), create && eventsOn ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
28040
28619
|
className: labelCls3
|
|
28041
28620
|
}, "Event"), /* @__PURE__ */ React.createElement("select", {
|
|
28042
28621
|
value: eventId ?? "",
|
|
@@ -28132,7 +28711,8 @@ function ProductEditPage({ productId }) {
|
|
|
28132
28711
|
}, "Status"), /* @__PURE__ */ React.createElement("select", {
|
|
28133
28712
|
value: status,
|
|
28134
28713
|
onChange: /* @__PURE__ */ __name((e) => setStatus(e.target.value), "onChange"),
|
|
28135
|
-
className: inputCls3
|
|
28714
|
+
className: inputCls3,
|
|
28715
|
+
disabled: approvalOn && vendorPortal && (approvalStatus === "pending" || approvalStatus === "rejected")
|
|
28136
28716
|
}, /* @__PURE__ */ React.createElement("option", {
|
|
28137
28717
|
value: "draft"
|
|
28138
28718
|
}, "Draft"), /* @__PURE__ */ React.createElement("option", {
|
|
@@ -28141,7 +28721,11 @@ function ProductEditPage({ productId }) {
|
|
|
28141
28721
|
value: "reserved"
|
|
28142
28722
|
}, "Reserved"), /* @__PURE__ */ React.createElement("option", {
|
|
28143
28723
|
value: "sold"
|
|
28144
|
-
}, "Sold"))
|
|
28724
|
+
}, "Sold")), approvalOn && vendorPortal && approvalStatus === "pending" ? /* @__PURE__ */ React.createElement("p", {
|
|
28725
|
+
className: "mt-1 text-xs text-gray-500"
|
|
28726
|
+
}, "Waiting for admin approval. The product goes live when approved.") : null, approvalOn && vendorPortal && approvalStatus === "rejected" ? /* @__PURE__ */ React.createElement("p", {
|
|
28727
|
+
className: "mt-1 text-xs text-red-600"
|
|
28728
|
+
}, "Rejected", rejectionReason ? `: ${rejectionReason}` : "", ".") : null)))), /* @__PURE__ */ React.createElement(ProductVariantsSection, {
|
|
28145
28729
|
hasVariants,
|
|
28146
28730
|
onHasVariantsChange: setHasVariants,
|
|
28147
28731
|
variantOptionRows,
|
|
@@ -28268,14 +28852,11 @@ function ProductEditPage({ productId }) {
|
|
|
28268
28852
|
className: "flex flex-wrap items-start gap-2 p-2 bg-white rounded border border-gray-200"
|
|
28269
28853
|
}, /* @__PURE__ */ React.createElement("div", {
|
|
28270
28854
|
className: "flex-1 min-w-[200px]"
|
|
28271
|
-
}, /* @__PURE__ */ React.createElement(
|
|
28272
|
-
|
|
28273
|
-
}, "Image URL"), /* @__PURE__ */ React.createElement("input", {
|
|
28274
|
-
type: "url",
|
|
28855
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
28856
|
+
label: "Image",
|
|
28275
28857
|
value: row.url,
|
|
28276
|
-
onChange: /* @__PURE__ */ __name((
|
|
28277
|
-
|
|
28278
|
-
placeholder: "https://..."
|
|
28858
|
+
onChange: /* @__PURE__ */ __name((v) => setImage(i, "url", v), "onChange"),
|
|
28859
|
+
inputClassName: inputCls3
|
|
28279
28860
|
})), /* @__PURE__ */ React.createElement("div", {
|
|
28280
28861
|
className: "flex-1 min-w-[120px]"
|
|
28281
28862
|
}, /* @__PURE__ */ React.createElement("label", {
|
|
@@ -28354,6 +28935,8 @@ var init_ProductEditPage = __esm({
|
|
|
28354
28935
|
"use client";
|
|
28355
28936
|
init_vendor_scope();
|
|
28356
28937
|
init_admin_list_return_url();
|
|
28938
|
+
init_dialog();
|
|
28939
|
+
init_button();
|
|
28357
28940
|
init_SeoSection();
|
|
28358
28941
|
init_DetailPageLayout();
|
|
28359
28942
|
init_DetailPageHeader();
|
|
@@ -28364,6 +28947,8 @@ var init_ProductEditPage = __esm({
|
|
|
28364
28947
|
init_inventory_validation();
|
|
28365
28948
|
init_category_item_label();
|
|
28366
28949
|
init_use_category_collections();
|
|
28950
|
+
init_ImageOrUrlField();
|
|
28951
|
+
init_admin_config_context();
|
|
28367
28952
|
init_ProductVariantsSection();
|
|
28368
28953
|
init_product_variants();
|
|
28369
28954
|
__name(parseCategoryIdFromReturnUrl, "parseCategoryIdFromReturnUrl");
|
|
@@ -28633,12 +29218,6 @@ function CollectionEditPage({ collectionId }) {
|
|
|
28633
29218
|
]);
|
|
28634
29219
|
return;
|
|
28635
29220
|
}
|
|
28636
|
-
if (create && !categoryId) {
|
|
28637
|
-
setErrors([
|
|
28638
|
-
"Category is required"
|
|
28639
|
-
]);
|
|
28640
|
-
return;
|
|
28641
|
-
}
|
|
28642
29221
|
setSaving(true);
|
|
28643
29222
|
try {
|
|
28644
29223
|
const savedSeoId = await saveSeo(seo, slug.trim(), seoId);
|
|
@@ -28859,14 +29438,11 @@ function CollectionEditPage({ collectionId }) {
|
|
|
28859
29438
|
onChange: /* @__PURE__ */ __name((e) => setDescription(e.target.value), "onChange"),
|
|
28860
29439
|
className: `${inputCls4} min-h-[80px]`,
|
|
28861
29440
|
rows: 3
|
|
28862
|
-
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
|
|
28863
|
-
|
|
28864
|
-
}, "Cover image URL"), /* @__PURE__ */ React.createElement("input", {
|
|
28865
|
-
type: "url",
|
|
29441
|
+
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
29442
|
+
label: "Cover image",
|
|
28866
29443
|
value: image,
|
|
28867
|
-
onChange:
|
|
28868
|
-
|
|
28869
|
-
placeholder: "https://..."
|
|
29444
|
+
onChange: setImage,
|
|
29445
|
+
inputClassName: inputCls4
|
|
28870
29446
|
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
28871
29447
|
className: labelCls4
|
|
28872
29448
|
}, "Sort order"), /* @__PURE__ */ React.createElement("input", {
|
|
@@ -28893,17 +29469,24 @@ function CollectionEditPage({ collectionId }) {
|
|
|
28893
29469
|
className: "text-xs font-medium text-gray-700 mb-2"
|
|
28894
29470
|
}, "Hero carousel"), heroSlides.map((slide, i) => /* @__PURE__ */ React.createElement("div", {
|
|
28895
29471
|
key: i,
|
|
28896
|
-
className: "flex flex-wrap gap-2 mb-3 p-2 bg-white rounded border"
|
|
28897
|
-
}, /* @__PURE__ */ React.createElement("
|
|
29472
|
+
className: "flex flex-wrap gap-2 mb-3 p-2 bg-white rounded border items-start"
|
|
29473
|
+
}, slide.type === "image" ? /* @__PURE__ */ React.createElement("div", {
|
|
29474
|
+
className: "flex-1 min-w-[200px]"
|
|
29475
|
+
}, /* @__PURE__ */ React.createElement(ImageOrUrlField, {
|
|
29476
|
+
label: "Slide image",
|
|
29477
|
+
value: slide.url,
|
|
29478
|
+
onChange: /* @__PURE__ */ __name((v) => updateHeroSlide(i, "url", v), "onChange"),
|
|
29479
|
+
inputClassName: inputCls4
|
|
29480
|
+
})) : /* @__PURE__ */ React.createElement("input", {
|
|
28898
29481
|
type: "url",
|
|
28899
29482
|
value: slide.url,
|
|
28900
29483
|
onChange: /* @__PURE__ */ __name((e) => updateHeroSlide(i, "url", e.target.value), "onChange"),
|
|
28901
|
-
placeholder: "
|
|
29484
|
+
placeholder: "Video URL",
|
|
28902
29485
|
className: `${inputCls4} flex-1 min-w-[200px]`
|
|
28903
29486
|
}), /* @__PURE__ */ React.createElement("select", {
|
|
28904
29487
|
value: slide.type,
|
|
28905
29488
|
onChange: /* @__PURE__ */ __name((e) => updateHeroSlide(i, "type", e.target.value), "onChange"),
|
|
28906
|
-
className: `${inputCls4} w-24`
|
|
29489
|
+
className: `${inputCls4} w-24 mt-6`
|
|
28907
29490
|
}, /* @__PURE__ */ React.createElement("option", {
|
|
28908
29491
|
value: "image"
|
|
28909
29492
|
}, "Image"), /* @__PURE__ */ React.createElement("option", {
|
|
@@ -28913,11 +29496,11 @@ function CollectionEditPage({ collectionId }) {
|
|
|
28913
29496
|
value: slide.caption,
|
|
28914
29497
|
onChange: /* @__PURE__ */ __name((e) => updateHeroSlide(i, "caption", e.target.value), "onChange"),
|
|
28915
29498
|
placeholder: "Caption",
|
|
28916
|
-
className: `${inputCls4} flex-1 min-w-[120px]`
|
|
29499
|
+
className: `${inputCls4} flex-1 min-w-[120px] mt-6`
|
|
28917
29500
|
}), /* @__PURE__ */ React.createElement("button", {
|
|
28918
29501
|
type: "button",
|
|
28919
29502
|
onClick: /* @__PURE__ */ __name(() => removeHeroSlide(i), "onClick"),
|
|
28920
|
-
className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0"
|
|
29503
|
+
className: "p-2 text-gray-400 hover:text-red-600 rounded shrink-0 mt-6"
|
|
28921
29504
|
}, /* @__PURE__ */ React.createElement(Trash2, {
|
|
28922
29505
|
className: "h-4 w-4"
|
|
28923
29506
|
})))), /* @__PURE__ */ React.createElement("button", {
|
|
@@ -29044,6 +29627,7 @@ var init_CollectionEditPage = __esm({
|
|
|
29044
29627
|
init_use_catalog_categories();
|
|
29045
29628
|
init_admin_config_context();
|
|
29046
29629
|
init_category_related_product_labels();
|
|
29630
|
+
init_ImageOrUrlField();
|
|
29047
29631
|
isCreate3 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
29048
29632
|
emptySlide = /* @__PURE__ */ __name(() => ({
|
|
29049
29633
|
url: "",
|
|
@@ -29061,116 +29645,6 @@ var init_CollectionEditPage = __esm({
|
|
|
29061
29645
|
__name(CollectionEditPage, "CollectionEditPage");
|
|
29062
29646
|
}
|
|
29063
29647
|
});
|
|
29064
|
-
function ImageOrUrlField({ label, value, onChange, placeholder = "https://\u2026", inputClassName = "w-full rounded-md border border-gray-300 px-2 py-1.5 text-sm", labelClassName = "block text-xs font-medium text-gray-600 mb-1", previewVariant = "banner", maxSizeMb = 10 }) {
|
|
29065
|
-
const fileInputRef = useRef(null);
|
|
29066
|
-
const [isUploading, setIsUploading] = useState(false);
|
|
29067
|
-
const [error, setError] = useState(null);
|
|
29068
|
-
const previewCls = previewVariant === "logo" ? "h-20 w-20 rounded-md border border-gray-200 bg-white object-contain" : "max-h-32 w-full rounded-md border border-gray-200 bg-gray-50 object-cover";
|
|
29069
|
-
const handleUpload = useCallback(async (file) => {
|
|
29070
|
-
setError(null);
|
|
29071
|
-
if (!ACCEPTED_TYPES.includes(file.type)) {
|
|
29072
|
-
setError(`Unsupported file type. Use: ${ACCEPTED_TYPES.map((t) => t.replace("image/", "")).join(", ")}`);
|
|
29073
|
-
return;
|
|
29074
|
-
}
|
|
29075
|
-
if (file.size > maxSizeMb * 1024 * 1024) {
|
|
29076
|
-
setError(`File must be under ${maxSizeMb}MB`);
|
|
29077
|
-
return;
|
|
29078
|
-
}
|
|
29079
|
-
setIsUploading(true);
|
|
29080
|
-
try {
|
|
29081
|
-
const formData = new FormData();
|
|
29082
|
-
formData.append("file", file);
|
|
29083
|
-
const response = await fetch("/api/upload", {
|
|
29084
|
-
method: "POST",
|
|
29085
|
-
body: formData
|
|
29086
|
-
});
|
|
29087
|
-
const data = await response.json();
|
|
29088
|
-
if (!response.ok) {
|
|
29089
|
-
throw new Error(data.error || data.details || "Upload failed");
|
|
29090
|
-
}
|
|
29091
|
-
onChange(data.filePath ?? "");
|
|
29092
|
-
} catch (err) {
|
|
29093
|
-
setError(err instanceof Error ? err.message : "Upload failed");
|
|
29094
|
-
} finally {
|
|
29095
|
-
setIsUploading(false);
|
|
29096
|
-
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
29097
|
-
}
|
|
29098
|
-
}, [
|
|
29099
|
-
maxSizeMb,
|
|
29100
|
-
onChange
|
|
29101
|
-
]);
|
|
29102
|
-
const onFileChange = useCallback((e) => {
|
|
29103
|
-
const file = e.target.files?.[0];
|
|
29104
|
-
if (file) void handleUpload(file);
|
|
29105
|
-
}, [
|
|
29106
|
-
handleUpload
|
|
29107
|
-
]);
|
|
29108
|
-
const trimmed = value.trim();
|
|
29109
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
29110
|
-
className: "space-y-2"
|
|
29111
|
-
}, /* @__PURE__ */ React.createElement("label", {
|
|
29112
|
-
className: labelClassName
|
|
29113
|
-
}, label), trimmed ? /* @__PURE__ */ React.createElement("div", {
|
|
29114
|
-
className: "flex items-start gap-3"
|
|
29115
|
-
}, /* @__PURE__ */ React.createElement("img", {
|
|
29116
|
-
src: trimmed,
|
|
29117
|
-
alt: label,
|
|
29118
|
-
className: previewCls,
|
|
29119
|
-
onError: /* @__PURE__ */ __name((e) => {
|
|
29120
|
-
e.currentTarget.style.display = "none";
|
|
29121
|
-
}, "onError")
|
|
29122
|
-
}), /* @__PURE__ */ React.createElement("button", {
|
|
29123
|
-
type: "button",
|
|
29124
|
-
onClick: /* @__PURE__ */ __name(() => onChange(""), "onClick"),
|
|
29125
|
-
className: "inline-flex items-center gap-1 rounded border border-gray-300 bg-white px-2 py-1 text-xs text-gray-600 hover:bg-gray-50"
|
|
29126
|
-
}, /* @__PURE__ */ React.createElement(X, {
|
|
29127
|
-
className: "h-3 w-3"
|
|
29128
|
-
}), "Clear")) : null, /* @__PURE__ */ React.createElement("div", {
|
|
29129
|
-
className: "flex flex-wrap gap-2"
|
|
29130
|
-
}, /* @__PURE__ */ React.createElement("input", {
|
|
29131
|
-
type: "url",
|
|
29132
|
-
value,
|
|
29133
|
-
onChange: /* @__PURE__ */ __name((e) => {
|
|
29134
|
-
setError(null);
|
|
29135
|
-
onChange(e.target.value);
|
|
29136
|
-
}, "onChange"),
|
|
29137
|
-
placeholder,
|
|
29138
|
-
className: `${inputClassName} min-w-0 flex-1`
|
|
29139
|
-
}), /* @__PURE__ */ React.createElement("input", {
|
|
29140
|
-
ref: fileInputRef,
|
|
29141
|
-
type: "file",
|
|
29142
|
-
accept: ACCEPTED_TYPES.join(","),
|
|
29143
|
-
onChange: onFileChange,
|
|
29144
|
-
className: "hidden",
|
|
29145
|
-
disabled: isUploading
|
|
29146
|
-
}), /* @__PURE__ */ React.createElement("button", {
|
|
29147
|
-
type: "button",
|
|
29148
|
-
onClick: /* @__PURE__ */ __name(() => fileInputRef.current?.click(), "onClick"),
|
|
29149
|
-
disabled: isUploading,
|
|
29150
|
-
className: "inline-flex shrink-0 items-center gap-1.5 rounded-md border border-gray-300 bg-white px-3 py-1.5 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
|
|
29151
|
-
}, /* @__PURE__ */ React.createElement(Upload, {
|
|
29152
|
-
className: "h-3.5 w-3.5"
|
|
29153
|
-
}), isUploading ? "Uploading\u2026" : "Upload")), error ? /* @__PURE__ */ React.createElement("p", {
|
|
29154
|
-
className: "flex items-center gap-1.5 text-xs text-red-600"
|
|
29155
|
-
}, /* @__PURE__ */ React.createElement(AlertCircle, {
|
|
29156
|
-
className: "h-3.5 w-3.5 shrink-0"
|
|
29157
|
-
}), error) : /* @__PURE__ */ React.createElement("p", {
|
|
29158
|
-
className: "text-xs text-gray-500"
|
|
29159
|
-
}, "Paste a URL or upload an image (PNG, JPG, GIF, WEBP up to ", maxSizeMb, "MB)"));
|
|
29160
|
-
}
|
|
29161
|
-
var ACCEPTED_TYPES;
|
|
29162
|
-
var init_ImageOrUrlField = __esm({
|
|
29163
|
-
"src/components/Admin/ImageOrUrlField.tsx"() {
|
|
29164
|
-
"use client";
|
|
29165
|
-
ACCEPTED_TYPES = [
|
|
29166
|
-
"image/jpeg",
|
|
29167
|
-
"image/png",
|
|
29168
|
-
"image/gif",
|
|
29169
|
-
"image/webp"
|
|
29170
|
-
];
|
|
29171
|
-
__name(ImageOrUrlField, "ImageOrUrlField");
|
|
29172
|
-
}
|
|
29173
|
-
});
|
|
29174
29648
|
function AttachProductModal({ open, onOpenChange, categoryId, categoryName, excludeProductIds = [], onAttach }) {
|
|
29175
29649
|
const [attachingId, setAttachingId] = useState(null);
|
|
29176
29650
|
const [error, setError] = useState(null);
|
|
@@ -30115,6 +30589,10 @@ function combineCityCountry(city, country) {
|
|
|
30115
30589
|
function EventEditPage({ eventId }) {
|
|
30116
30590
|
const router = useRouter();
|
|
30117
30591
|
const searchParams = useSearchParams();
|
|
30592
|
+
const { data: session } = useSession();
|
|
30593
|
+
const { requireEventApproval } = useContext(AdminConfigContext);
|
|
30594
|
+
const approvalOn = requireEventApproval === true;
|
|
30595
|
+
const vendorPortal = isVendorPortalUser(session?.user);
|
|
30118
30596
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/events";
|
|
30119
30597
|
const create = isCreate4(eventId);
|
|
30120
30598
|
const dupParam = searchParams.get("duplicateFrom");
|
|
@@ -30127,6 +30605,11 @@ function EventEditPage({ eventId }) {
|
|
|
30127
30605
|
const [slug, setSlug] = useState("");
|
|
30128
30606
|
const [description, setDescription] = useState("");
|
|
30129
30607
|
const [isActive, setIsActive] = useState(true);
|
|
30608
|
+
const [approvalStatus, setApprovalStatus] = useState("pending");
|
|
30609
|
+
const [rejectionReason, setRejectionReason] = useState("");
|
|
30610
|
+
const [rejectModalOpen, setRejectModalOpen] = useState(false);
|
|
30611
|
+
const [rejectDraft, setRejectDraft] = useState("");
|
|
30612
|
+
const approvalBeforeRejectRef = useRef("pending");
|
|
30130
30613
|
const [comingSoon, setComingSoon] = useState(false);
|
|
30131
30614
|
const [bannerImageUrl, setBannerImageUrl] = useState("");
|
|
30132
30615
|
const [logoUrl, setLogoUrl] = useState("");
|
|
@@ -30212,6 +30695,16 @@ function EventEditPage({ eventId }) {
|
|
|
30212
30695
|
cancelled = true;
|
|
30213
30696
|
};
|
|
30214
30697
|
}, []);
|
|
30698
|
+
useEffect(() => {
|
|
30699
|
+
if (create && vendorPortal && approvalOn) {
|
|
30700
|
+
setApprovalStatus("pending");
|
|
30701
|
+
setIsActive(false);
|
|
30702
|
+
}
|
|
30703
|
+
}, [
|
|
30704
|
+
create,
|
|
30705
|
+
vendorPortal,
|
|
30706
|
+
approvalOn
|
|
30707
|
+
]);
|
|
30215
30708
|
useEffect(() => {
|
|
30216
30709
|
let cancelled = false;
|
|
30217
30710
|
(async () => {
|
|
@@ -30233,6 +30726,8 @@ function EventEditPage({ eventId }) {
|
|
|
30233
30726
|
setSlug(data.slug ?? "");
|
|
30234
30727
|
setDescription(data.description ?? "");
|
|
30235
30728
|
setIsActive(data.isActive ?? true);
|
|
30729
|
+
setApprovalStatus(typeof data.approvalStatus === "string" && data.approvalStatus ? data.approvalStatus : "pending");
|
|
30730
|
+
setRejectionReason(typeof data.rejectionReason === "string" ? data.rejectionReason : "");
|
|
30236
30731
|
setComingSoon(data.comingSoon ?? false);
|
|
30237
30732
|
setBannerImageUrl(data.bannerImageUrl ?? "");
|
|
30238
30733
|
setLogoUrl(data.logoUrl ?? "");
|
|
@@ -30344,11 +30839,11 @@ function EventEditPage({ eventId }) {
|
|
|
30344
30839
|
setErrors(nextErrors);
|
|
30345
30840
|
return null;
|
|
30346
30841
|
}
|
|
30347
|
-
|
|
30842
|
+
const payload = {
|
|
30348
30843
|
name: name.trim(),
|
|
30349
30844
|
slug: slug.trim(),
|
|
30350
30845
|
description: description.trim() || null,
|
|
30351
|
-
isActive,
|
|
30846
|
+
isActive: create && vendorPortal && approvalOn ? false : isActive,
|
|
30352
30847
|
comingSoon,
|
|
30353
30848
|
bannerImageUrl: bannerImageUrl.trim() || null,
|
|
30354
30849
|
logoUrl: logoUrl.trim() || null,
|
|
@@ -30386,9 +30881,55 @@ function EventEditPage({ eventId }) {
|
|
|
30386
30881
|
sortOrder,
|
|
30387
30882
|
contactFormId
|
|
30388
30883
|
};
|
|
30884
|
+
if (approvalOn) {
|
|
30885
|
+
if (vendorPortal && create) {
|
|
30886
|
+
payload.approvalStatus = "pending";
|
|
30887
|
+
} else if (!vendorPortal) {
|
|
30888
|
+
payload.approvalStatus = approvalStatus;
|
|
30889
|
+
if (approvalStatus === "rejected") {
|
|
30890
|
+
payload.rejectionReason = rejectionReason.trim();
|
|
30891
|
+
}
|
|
30892
|
+
}
|
|
30893
|
+
}
|
|
30894
|
+
return payload;
|
|
30389
30895
|
}, "buildPayload");
|
|
30896
|
+
const openRejectModal = /* @__PURE__ */ __name((fromStatus) => {
|
|
30897
|
+
approvalBeforeRejectRef.current = fromStatus === "rejected" ? "pending" : fromStatus;
|
|
30898
|
+
setRejectDraft(rejectionReason);
|
|
30899
|
+
setApprovalStatus("rejected");
|
|
30900
|
+
setRejectModalOpen(true);
|
|
30901
|
+
}, "openRejectModal");
|
|
30902
|
+
const confirmRejectReason = /* @__PURE__ */ __name(() => {
|
|
30903
|
+
const reason = rejectDraft.trim();
|
|
30904
|
+
if (!reason) return;
|
|
30905
|
+
setRejectionReason(reason);
|
|
30906
|
+
setRejectModalOpen(false);
|
|
30907
|
+
}, "confirmRejectReason");
|
|
30908
|
+
const cancelRejectModal = /* @__PURE__ */ __name(() => {
|
|
30909
|
+
if (!rejectionReason.trim()) {
|
|
30910
|
+
setApprovalStatus(approvalBeforeRejectRef.current || "pending");
|
|
30911
|
+
}
|
|
30912
|
+
setRejectDraft(rejectionReason);
|
|
30913
|
+
setRejectModalOpen(false);
|
|
30914
|
+
}, "cancelRejectModal");
|
|
30915
|
+
const handleApprovalSelect = /* @__PURE__ */ __name((value) => {
|
|
30916
|
+
if (value === "rejected") {
|
|
30917
|
+
openRejectModal(approvalStatus);
|
|
30918
|
+
return;
|
|
30919
|
+
}
|
|
30920
|
+
setApprovalStatus(value);
|
|
30921
|
+
if (value !== "rejected") setRejectionReason("");
|
|
30922
|
+
}, "handleApprovalSelect");
|
|
30390
30923
|
const handleSave = /* @__PURE__ */ __name(async () => {
|
|
30391
30924
|
setErrors([]);
|
|
30925
|
+
if (approvalOn && !vendorPortal && approvalStatus === "rejected" && !rejectionReason.trim()) {
|
|
30926
|
+
setRejectDraft("");
|
|
30927
|
+
setRejectModalOpen(true);
|
|
30928
|
+
setErrors([
|
|
30929
|
+
"Rejection reason is required"
|
|
30930
|
+
]);
|
|
30931
|
+
return;
|
|
30932
|
+
}
|
|
30392
30933
|
const payload = buildPayload();
|
|
30393
30934
|
if (!payload) return;
|
|
30394
30935
|
setSaving(true);
|
|
@@ -30408,6 +30949,9 @@ function EventEditPage({ eventId }) {
|
|
|
30408
30949
|
return;
|
|
30409
30950
|
}
|
|
30410
30951
|
const saved = await res.json();
|
|
30952
|
+
if (typeof saved.isActive === "boolean") setIsActive(saved.isActive);
|
|
30953
|
+
if (typeof saved.approvalStatus === "string") setApprovalStatus(saved.approvalStatus);
|
|
30954
|
+
if (approvalStatus === "approved") setRejectionReason("");
|
|
30411
30955
|
const savedId = create ? saved.id : Number(eventId);
|
|
30412
30956
|
if (savedId != null && !Number.isNaN(savedId)) {
|
|
30413
30957
|
router.push(`/admin/events/${savedId}/edit?from=${encodeURIComponent(listReturnUrl)}`);
|
|
@@ -30470,19 +31014,66 @@ function EventEditPage({ eventId }) {
|
|
|
30470
31014
|
title: create ? "Add event" : "Edit event",
|
|
30471
31015
|
subtitle: create ? "Create a new event" : "Update event details and tickets",
|
|
30472
31016
|
closeHref: listReturnUrl,
|
|
31017
|
+
headerExtra: approvalOn && !vendorPortal ? /* @__PURE__ */ React.createElement("div", {
|
|
31018
|
+
className: "flex items-center gap-2"
|
|
31019
|
+
}, /* @__PURE__ */ React.createElement("select", {
|
|
31020
|
+
value: approvalStatus,
|
|
31021
|
+
onChange: /* @__PURE__ */ __name((e) => handleApprovalSelect(e.target.value), "onChange"),
|
|
31022
|
+
className: "h-8 rounded-md border border-gray-600 bg-gray-900 text-white text-xs px-2 max-w-[10rem]",
|
|
31023
|
+
"aria-label": "Approval status"
|
|
31024
|
+
}, /* @__PURE__ */ React.createElement("option", {
|
|
31025
|
+
value: "pending"
|
|
31026
|
+
}, "Pending"), /* @__PURE__ */ React.createElement("option", {
|
|
31027
|
+
value: "approved"
|
|
31028
|
+
}, "Approve"), /* @__PURE__ */ React.createElement("option", {
|
|
31029
|
+
value: "rejected"
|
|
31030
|
+
}, "Reject")), approvalStatus === "rejected" ? /* @__PURE__ */ React.createElement("button", {
|
|
31031
|
+
type: "button",
|
|
31032
|
+
onClick: /* @__PURE__ */ __name(() => openRejectModal("rejected"), "onClick"),
|
|
31033
|
+
className: "text-xs text-amber-300 hover:text-amber-200 underline underline-offset-2 max-w-[9rem] truncate",
|
|
31034
|
+
title: rejectionReason || "Add rejection reason"
|
|
31035
|
+
}, rejectionReason.trim() ? "Edit reason" : "Add reason") : null) : approvalOn && vendorPortal ? /* @__PURE__ */ React.createElement("span", {
|
|
31036
|
+
className: "text-xs text-gray-300 capitalize hidden sm:inline"
|
|
31037
|
+
}, approvalStatus.replace(/_/g, " "), approvalStatus === "rejected" && rejectionReason ? ` \u2014 ${rejectionReason}` : "") : null,
|
|
30473
31038
|
menuItems: [
|
|
30474
31039
|
{
|
|
30475
31040
|
label: saving ? "Saving..." : "Save",
|
|
30476
31041
|
icon: Save,
|
|
30477
31042
|
onClick: handleSave
|
|
30478
31043
|
},
|
|
30479
|
-
|
|
30480
|
-
|
|
30481
|
-
|
|
30482
|
-
|
|
30483
|
-
|
|
31044
|
+
...approvalOn && vendorPortal && (approvalStatus === "pending" || approvalStatus === "rejected") ? [] : [
|
|
31045
|
+
{
|
|
31046
|
+
label: isActive ? "Deactivate" : "Activate",
|
|
31047
|
+
icon: Power,
|
|
31048
|
+
onClick: /* @__PURE__ */ __name(() => setIsActive(!isActive), "onClick")
|
|
31049
|
+
}
|
|
31050
|
+
]
|
|
30484
31051
|
]
|
|
30485
|
-
}),
|
|
31052
|
+
}), /* @__PURE__ */ React.createElement(Dialog, {
|
|
31053
|
+
open: rejectModalOpen,
|
|
31054
|
+
onOpenChange: /* @__PURE__ */ __name((open) => {
|
|
31055
|
+
if (!open) cancelRejectModal();
|
|
31056
|
+
}, "onOpenChange")
|
|
31057
|
+
}, /* @__PURE__ */ React.createElement(DialogContent, {
|
|
31058
|
+
className: "max-w-md"
|
|
31059
|
+
}, /* @__PURE__ */ React.createElement(DialogHeader, null, /* @__PURE__ */ React.createElement(DialogTitle, null, "Rejection reason"), /* @__PURE__ */ React.createElement(DialogDescription, null, "Explain what the vendor needs to fix. This is required before you can save a rejected event.")), /* @__PURE__ */ React.createElement("textarea", {
|
|
31060
|
+
value: rejectDraft,
|
|
31061
|
+
onChange: /* @__PURE__ */ __name((e) => setRejectDraft(e.target.value), "onChange"),
|
|
31062
|
+
className: "w-full min-h-[100px] rounded-md border border-gray-300 px-3 py-2 text-sm",
|
|
31063
|
+
placeholder: "Explain what needs to change\u2026",
|
|
31064
|
+
autoFocus: true
|
|
31065
|
+
}), /* @__PURE__ */ React.createElement(DialogFooter, {
|
|
31066
|
+
className: "gap-2 sm:gap-0"
|
|
31067
|
+
}, /* @__PURE__ */ React.createElement(Button, {
|
|
31068
|
+
type: "button",
|
|
31069
|
+
variant: "outline",
|
|
31070
|
+
onClick: cancelRejectModal
|
|
31071
|
+
}, "Cancel"), /* @__PURE__ */ React.createElement(Button, {
|
|
31072
|
+
type: "button",
|
|
31073
|
+
variant: "destructive",
|
|
31074
|
+
disabled: !rejectDraft.trim(),
|
|
31075
|
+
onClick: confirmRejectReason
|
|
31076
|
+
}, "Confirm reject")))), !create && logoUrl.trim() ? /* @__PURE__ */ React.createElement("div", {
|
|
30486
31077
|
className: "flex items-center gap-3 px-4 sm:px-6 py-3 border-b border-gray-100 bg-gray-50/80"
|
|
30487
31078
|
}, /* @__PURE__ */ React.createElement("img", {
|
|
30488
31079
|
src: logoUrl.trim(),
|
|
@@ -30841,11 +31432,15 @@ var init_EventEditPage = __esm({
|
|
|
30841
31432
|
"src/admin/pages/EventEditPage.tsx"() {
|
|
30842
31433
|
"use client";
|
|
30843
31434
|
init_admin_list_return_url();
|
|
31435
|
+
init_vendor_scope();
|
|
30844
31436
|
init_DetailPageLayout();
|
|
30845
31437
|
init_DetailPageHeader();
|
|
30846
31438
|
init_ImageOrUrlField();
|
|
30847
31439
|
init_JoditRichText();
|
|
30848
31440
|
init_EventProductsSection();
|
|
31441
|
+
init_admin_config_context();
|
|
31442
|
+
init_dialog();
|
|
31443
|
+
init_button();
|
|
30849
31444
|
init_EventManagementFields();
|
|
30850
31445
|
init_event_named_lists();
|
|
30851
31446
|
init_social_media_links();
|
|
@@ -30921,6 +31516,8 @@ async function validateComboProductInventory(productIds) {
|
|
|
30921
31516
|
function ComboEditPage({ comboId }) {
|
|
30922
31517
|
const router = useRouter();
|
|
30923
31518
|
const searchParams = useSearchParams();
|
|
31519
|
+
const { eventsEnabled } = useContext(AdminConfigContext);
|
|
31520
|
+
const eventsOn = eventsEnabled !== false;
|
|
30924
31521
|
const listReturnUrl = safeAdminListReturnUrl(searchParams.get("from")) ?? "/admin/combos";
|
|
30925
31522
|
const create = isCreate5(comboId);
|
|
30926
31523
|
const duplicateFrom = searchParams.get("duplicateFrom")?.trim();
|
|
@@ -30942,8 +31539,9 @@ function ComboEditPage({ comboId }) {
|
|
|
30942
31539
|
const [productOptions, setProductOptions] = useState([]);
|
|
30943
31540
|
const [fixedItems, setFixedItems] = useState([]);
|
|
30944
31541
|
const [addonItems, setAddonItems] = useState([]);
|
|
31542
|
+
const canPickProducts = !eventsOn || Boolean(eventId);
|
|
30945
31543
|
useEffect(() => {
|
|
30946
|
-
if (!eventId) {
|
|
31544
|
+
if (!eventsOn || !eventId) {
|
|
30947
31545
|
setDefaultCurrency("INR");
|
|
30948
31546
|
return;
|
|
30949
31547
|
}
|
|
@@ -30955,9 +31553,14 @@ function ComboEditPage({ comboId }) {
|
|
|
30955
31553
|
cancelled = true;
|
|
30956
31554
|
};
|
|
30957
31555
|
}, [
|
|
30958
|
-
eventId
|
|
31556
|
+
eventId,
|
|
31557
|
+
eventsOn
|
|
30959
31558
|
]);
|
|
30960
31559
|
useEffect(() => {
|
|
31560
|
+
if (!eventsOn) {
|
|
31561
|
+
setEventOptions([]);
|
|
31562
|
+
return;
|
|
31563
|
+
}
|
|
30961
31564
|
let cancelled = false;
|
|
30962
31565
|
(async () => {
|
|
30963
31566
|
try {
|
|
@@ -30977,45 +31580,63 @@ function ComboEditPage({ comboId }) {
|
|
|
30977
31580
|
return () => {
|
|
30978
31581
|
cancelled = true;
|
|
30979
31582
|
};
|
|
30980
|
-
}, [
|
|
31583
|
+
}, [
|
|
31584
|
+
eventsOn
|
|
31585
|
+
]);
|
|
30981
31586
|
useEffect(() => {
|
|
30982
|
-
if (!eventId) {
|
|
30983
|
-
setProductOptions([]);
|
|
30984
|
-
return;
|
|
30985
|
-
}
|
|
30986
31587
|
let cancelled = false;
|
|
30987
31588
|
(async () => {
|
|
30988
31589
|
try {
|
|
30989
|
-
|
|
30990
|
-
|
|
31590
|
+
if (eventsOn) {
|
|
31591
|
+
if (!eventId) {
|
|
31592
|
+
setProductOptions([]);
|
|
31593
|
+
return;
|
|
31594
|
+
}
|
|
31595
|
+
const res2 = await fetch(`/api/event_products?eventId=${eventId}&limit=500`);
|
|
31596
|
+
if (!res2.ok) return;
|
|
30991
31597
|
const data = await res2.json();
|
|
30992
|
-
if (
|
|
30993
|
-
|
|
30994
|
-
|
|
30995
|
-
|
|
30996
|
-
|
|
30997
|
-
const prodData = await prodRes.json();
|
|
30998
|
-
if (!cancelled && Array.isArray(prodData.data)) {
|
|
30999
|
-
const fetched = prodData.data.map((p) => ({
|
|
31000
|
-
value: String(p.id),
|
|
31001
|
-
label: p.name ?? p.title ?? `Product #${p.id}`
|
|
31002
|
-
}));
|
|
31003
|
-
setProductOptions((prev) => {
|
|
31004
|
-
const merged = [
|
|
31005
|
-
...fetched
|
|
31006
|
-
];
|
|
31007
|
-
for (const p of prev) {
|
|
31008
|
-
if (!merged.some((m) => m.value === p.value)) merged.push(p);
|
|
31009
|
-
}
|
|
31010
|
-
return merged;
|
|
31011
|
-
});
|
|
31012
|
-
}
|
|
31013
|
-
}
|
|
31014
|
-
} else {
|
|
31015
|
-
setProductOptions([]);
|
|
31016
|
-
}
|
|
31598
|
+
if (cancelled || !Array.isArray(data.data)) return;
|
|
31599
|
+
const productIds = data.data.map((ep) => ep.productId).filter(Boolean);
|
|
31600
|
+
if (productIds.length === 0) {
|
|
31601
|
+
setProductOptions([]);
|
|
31602
|
+
return;
|
|
31017
31603
|
}
|
|
31604
|
+
const prodRes2 = await fetch(`/api/products?ids=${productIds.join(",")}&limit=500`);
|
|
31605
|
+
if (!prodRes2.ok) return;
|
|
31606
|
+
const prodData2 = await prodRes2.json();
|
|
31607
|
+
if (cancelled || !Array.isArray(prodData2.data)) return;
|
|
31608
|
+
const fetched2 = prodData2.data.map((p) => ({
|
|
31609
|
+
value: String(p.id),
|
|
31610
|
+
label: p.name ?? p.title ?? `Product #${p.id}`
|
|
31611
|
+
}));
|
|
31612
|
+
setProductOptions((prev) => {
|
|
31613
|
+
const merged = [
|
|
31614
|
+
...fetched2
|
|
31615
|
+
];
|
|
31616
|
+
for (const p of prev) {
|
|
31617
|
+
if (!merged.some((m) => m.value === p.value)) merged.push(p);
|
|
31618
|
+
}
|
|
31619
|
+
return merged;
|
|
31620
|
+
});
|
|
31621
|
+
return;
|
|
31018
31622
|
}
|
|
31623
|
+
const prodRes = await fetch("/api/products?limit=500&sortField=name&sortOrder=asc");
|
|
31624
|
+
if (!prodRes.ok) return;
|
|
31625
|
+
const prodData = await prodRes.json();
|
|
31626
|
+
if (cancelled || !Array.isArray(prodData.data)) return;
|
|
31627
|
+
const fetched = prodData.data.map((p) => ({
|
|
31628
|
+
value: String(p.id),
|
|
31629
|
+
label: p.name ?? p.title ?? `Product #${p.id}`
|
|
31630
|
+
}));
|
|
31631
|
+
setProductOptions((prev) => {
|
|
31632
|
+
const merged = [
|
|
31633
|
+
...fetched
|
|
31634
|
+
];
|
|
31635
|
+
for (const p of prev) {
|
|
31636
|
+
if (!merged.some((m) => m.value === p.value)) merged.push(p);
|
|
31637
|
+
}
|
|
31638
|
+
return merged;
|
|
31639
|
+
});
|
|
31019
31640
|
} catch {
|
|
31020
31641
|
}
|
|
31021
31642
|
})();
|
|
@@ -31023,7 +31644,8 @@ function ComboEditPage({ comboId }) {
|
|
|
31023
31644
|
cancelled = true;
|
|
31024
31645
|
};
|
|
31025
31646
|
}, [
|
|
31026
|
-
eventId
|
|
31647
|
+
eventId,
|
|
31648
|
+
eventsOn
|
|
31027
31649
|
]);
|
|
31028
31650
|
useEffect(() => {
|
|
31029
31651
|
let cancelled = false;
|
|
@@ -31134,7 +31756,7 @@ function ComboEditPage({ comboId }) {
|
|
|
31134
31756
|
]);
|
|
31135
31757
|
return;
|
|
31136
31758
|
}
|
|
31137
|
-
if (!trimmedEventId || !/^\d+$/.test(trimmedEventId)) {
|
|
31759
|
+
if (eventsOn && (!trimmedEventId || !/^\d+$/.test(trimmedEventId))) {
|
|
31138
31760
|
setErrors([
|
|
31139
31761
|
"Event is required"
|
|
31140
31762
|
]);
|
|
@@ -31193,10 +31815,11 @@ function ComboEditPage({ comboId }) {
|
|
|
31193
31815
|
}
|
|
31194
31816
|
setSaving(true);
|
|
31195
31817
|
try {
|
|
31818
|
+
const resolvedEventId = trimmedEventId && /^\d+$/.test(trimmedEventId) ? Number(trimmedEventId) : null;
|
|
31196
31819
|
const payload = {
|
|
31197
31820
|
name: trimmedName,
|
|
31198
31821
|
desc: desc || null,
|
|
31199
|
-
eventId:
|
|
31822
|
+
eventId: resolvedEventId,
|
|
31200
31823
|
price,
|
|
31201
31824
|
currencyPrices: null,
|
|
31202
31825
|
minSelectableItems,
|
|
@@ -31290,7 +31913,7 @@ function ComboEditPage({ comboId }) {
|
|
|
31290
31913
|
value: desc,
|
|
31291
31914
|
onChange: /* @__PURE__ */ __name((e) => setDesc(e.target.value), "onChange"),
|
|
31292
31915
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm min-h-[100px]"
|
|
31293
|
-
})), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
31916
|
+
})), eventsOn ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
31294
31917
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
31295
31918
|
}, "Event *"), /* @__PURE__ */ React.createElement("select", {
|
|
31296
31919
|
value: eventId,
|
|
@@ -31305,7 +31928,7 @@ function ComboEditPage({ comboId }) {
|
|
|
31305
31928
|
}, "Select event"), eventOptions.map((o) => /* @__PURE__ */ React.createElement("option", {
|
|
31306
31929
|
key: o.value,
|
|
31307
31930
|
value: o.value
|
|
31308
|
-
}, o.label)))))),
|
|
31931
|
+
}, o.label)))) : null)), canPickProducts && /* @__PURE__ */ React.createElement("section", null, /* @__PURE__ */ React.createElement("h2", {
|
|
31309
31932
|
className: "text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2"
|
|
31310
31933
|
}, "Combo items"), /* @__PURE__ */ React.createElement("div", {
|
|
31311
31934
|
className: "min-w-0 overflow-hidden border border-gray-200 rounded-lg p-4 bg-gray-50/50 space-y-5"
|
|
@@ -31373,11 +31996,11 @@ function ComboEditPage({ comboId }) {
|
|
|
31373
31996
|
step: "0.01",
|
|
31374
31997
|
value: priceStr,
|
|
31375
31998
|
onChange: /* @__PURE__ */ __name((e) => setPriceStr(e.target.value), "onChange"),
|
|
31376
|
-
disabled: !
|
|
31999
|
+
disabled: !canPickProducts,
|
|
31377
32000
|
className: "w-full rounded-md border border-gray-300 px-3 py-2 text-sm disabled:bg-gray-100"
|
|
31378
32001
|
}), /* @__PURE__ */ React.createElement("p", {
|
|
31379
32002
|
className: "text-xs text-gray-400 mt-1"
|
|
31380
|
-
}, eventId ? "Other currencies use the event\u2019s supported currencies and exchange rates." : "Select an event to set the combo price.")), /* @__PURE__ */ React.createElement("div", {
|
|
32003
|
+
}, eventsOn ? eventId ? "Other currencies use the event\u2019s supported currencies and exchange rates." : "Select an event to set the combo price." : "Price uses the store default currency (INR unless configured otherwise).")), /* @__PURE__ */ React.createElement("div", {
|
|
31381
32004
|
className: "grid grid-cols-2 gap-4"
|
|
31382
32005
|
}, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", {
|
|
31383
32006
|
className: "block text-xs font-medium text-gray-600 mb-1"
|
|
@@ -31443,6 +32066,7 @@ var init_ComboEditPage = __esm({
|
|
|
31443
32066
|
init_DetailPageLayout();
|
|
31444
32067
|
init_DetailPageHeader();
|
|
31445
32068
|
init_inventory_validation();
|
|
32069
|
+
init_admin_config_context();
|
|
31446
32070
|
isCreate5 = /* @__PURE__ */ __name((id) => id === "create", "isCreate");
|
|
31447
32071
|
__name(formatDateTimeLocal, "formatDateTimeLocal");
|
|
31448
32072
|
__name(fetchEventDefaultCurrency, "fetchEventDefaultCurrency");
|
|
@@ -32277,9 +32901,9 @@ var VendorCategoryWorkspacePage_exports = {};
|
|
|
32277
32901
|
__export(VendorCategoryWorkspacePage_exports, {
|
|
32278
32902
|
default: () => VendorCategoryWorkspacePage
|
|
32279
32903
|
});
|
|
32280
|
-
function buildAdminProductColumns(base,
|
|
32904
|
+
function buildAdminProductColumns(base, showVendorColumn, eventsEnabled) {
|
|
32281
32905
|
const extraColumns = [
|
|
32282
|
-
...
|
|
32906
|
+
...showVendorColumn ? [
|
|
32283
32907
|
VENDOR_EXTRA_COLUMN
|
|
32284
32908
|
] : [],
|
|
32285
32909
|
...eventsEnabled ? [
|
|
@@ -32298,9 +32922,9 @@ function buildAdminProductColumns(base, multiVendorEnabled, eventsEnabled) {
|
|
|
32298
32922
|
...cols.slice(nameIdx + 1)
|
|
32299
32923
|
];
|
|
32300
32924
|
}
|
|
32301
|
-
function buildAllProductColumns(base,
|
|
32925
|
+
function buildAllProductColumns(base, showVendorColumn, eventsEnabled) {
|
|
32302
32926
|
const extraColumns = [
|
|
32303
|
-
...
|
|
32927
|
+
...showVendorColumn ? [
|
|
32304
32928
|
VENDOR_EXTRA_COLUMN
|
|
32305
32929
|
] : [],
|
|
32306
32930
|
...eventsEnabled ? [
|
|
@@ -32350,7 +32974,8 @@ function VendorCategoryWorkspacePage() {
|
|
|
32350
32974
|
const workspaceFrom = activeCategoryId ? `/admin/products?categoryId=${activeCategoryId}` : "/admin/products";
|
|
32351
32975
|
const itemLabel = activeCategory ? categorySingularName(activeCategory.name) : "Product";
|
|
32352
32976
|
const productColumns2 = useMemo(() => {
|
|
32353
|
-
const
|
|
32977
|
+
const showVendorColumn = multiVendorEnabled !== false && !vendorPortal;
|
|
32978
|
+
const base = showAllProducts ? buildAllProductColumns(STORE_CRUD_CONFIGS.products.columns, showVendorColumn, eventsEnabled !== false) : buildAdminProductColumns(STORE_CRUD_CONFIGS.products.columns, showVendorColumn, eventsEnabled !== false);
|
|
32354
32979
|
return withCollectionRelationApi(base, activeCategoryId, vendorPortal);
|
|
32355
32980
|
}, [
|
|
32356
32981
|
vendorPortal,
|
|
@@ -33676,7 +34301,7 @@ function CustomerPicker({ value, label, onChange }) {
|
|
|
33676
34301
|
className: "text-xs text-gray-400 shrink-0 truncate"
|
|
33677
34302
|
}, c.email ?? ""))))));
|
|
33678
34303
|
}
|
|
33679
|
-
function ConditionCard({ condition, onChange, onRemove }) {
|
|
34304
|
+
function ConditionCard({ condition, onChange, onRemove, eventsOn }) {
|
|
33680
34305
|
const iconMap = {
|
|
33681
34306
|
minAmount: /* @__PURE__ */ React.createElement(DollarSign, {
|
|
33682
34307
|
className: "h-3.5 w-3.5 text-blue-500"
|
|
@@ -33732,7 +34357,7 @@ function ConditionCard({ condition, onChange, onRemove }) {
|
|
|
33732
34357
|
value: "minQuantity"
|
|
33733
34358
|
}, "Minimum quantity"), /* @__PURE__ */ React.createElement(SelectItem, {
|
|
33734
34359
|
value: "productMinQuantity"
|
|
33735
|
-
}, "Product"), /* @__PURE__ */ React.createElement(SelectItem, {
|
|
34360
|
+
}, "Product"), (eventsOn || condition.kind === "events") && /* @__PURE__ */ React.createElement(SelectItem, {
|
|
33736
34361
|
value: "events"
|
|
33737
34362
|
}, "Events"), /* @__PURE__ */ React.createElement(SelectItem, {
|
|
33738
34363
|
value: "nthOrder"
|
|
@@ -33966,11 +34591,13 @@ function RewardCard({ reward, onChange, onRemove, discountType, discountValue, e
|
|
|
33966
34591
|
})));
|
|
33967
34592
|
}
|
|
33968
34593
|
function DiscountConditionsBuilder({ rules, onChange, discountType = "PERCENTAGE", discountValue = "" }) {
|
|
34594
|
+
const { eventsEnabled } = useContext(AdminConfigContext);
|
|
34595
|
+
const eventsOn = eventsEnabled !== false;
|
|
33969
34596
|
const parsed = ruleTreeToFriendly(rules);
|
|
33970
34597
|
const [groups, setGroups] = useState(parsed.groups);
|
|
33971
34598
|
const [groupOperator, setGroupOperator] = useState(parsed.groupOperator);
|
|
33972
34599
|
const [rewards, setRewards] = useState(parsed.rewards);
|
|
33973
|
-
const rewardEventId = groups.flatMap((g) => g.conditions).find((c) => c.kind === "events" && c.eventId != null)?.eventId ?? null;
|
|
34600
|
+
const rewardEventId = eventsOn ? groups.flatMap((g) => g.conditions).find((c) => c.kind === "events" && c.eventId != null)?.eventId ?? null : null;
|
|
33974
34601
|
useEffect(() => {
|
|
33975
34602
|
const missingNameIds = [];
|
|
33976
34603
|
for (const g of groups) {
|
|
@@ -34207,7 +34834,8 @@ function DiscountConditionsBuilder({ rules, onChange, discountType = "PERCENTAGE
|
|
|
34207
34834
|
})), /* @__PURE__ */ React.createElement(ConditionCard, {
|
|
34208
34835
|
condition: c,
|
|
34209
34836
|
onChange: /* @__PURE__ */ __name((updated) => updateCondition(group.id, c.id, updated), "onChange"),
|
|
34210
|
-
onRemove: /* @__PURE__ */ __name(() => removeCondition(group.id, c.id), "onRemove")
|
|
34837
|
+
onRemove: /* @__PURE__ */ __name(() => removeCondition(group.id, c.id), "onRemove"),
|
|
34838
|
+
eventsOn
|
|
34211
34839
|
})))), /* @__PURE__ */ React.createElement(Button, {
|
|
34212
34840
|
type: "button",
|
|
34213
34841
|
variant: "outline",
|
|
@@ -34270,6 +34898,7 @@ var init_DiscountsConditionsBuilder = __esm({
|
|
|
34270
34898
|
"use client";
|
|
34271
34899
|
init_button();
|
|
34272
34900
|
init_select();
|
|
34901
|
+
init_admin_config_context();
|
|
34273
34902
|
__name(uid, "uid");
|
|
34274
34903
|
__name(conditionToRule, "conditionToRule");
|
|
34275
34904
|
__name(rewardToRule, "rewardToRule");
|
|
@@ -36451,7 +37080,7 @@ function AdminPageResolver({ slug }) {
|
|
|
36451
37080
|
const searchParams = useSearchParams();
|
|
36452
37081
|
const { data: session } = useSession();
|
|
36453
37082
|
const vendorPortal = isVendorPortalUser(session?.user);
|
|
36454
|
-
const { customCrudConfigs, storeEnabled, multiVendorEnabled, eventsEnabled } = useContext(AdminConfigContext);
|
|
37083
|
+
const { customCrudConfigs, storeEnabled, multiVendorEnabled, eventsEnabled, vendorCanCreateCategories, vendorCanCreateCollections, vendorCanCreateBrands, requireProductApproval, requireEventApproval } = useContext(AdminConfigContext);
|
|
36455
37084
|
const key = slug?.[0] || "dashboard";
|
|
36456
37085
|
const [vendorOptions, setVendorOptions] = useState([]);
|
|
36457
37086
|
useEffect(() => {
|
|
@@ -36485,6 +37114,11 @@ function AdminPageResolver({ slug }) {
|
|
|
36485
37114
|
columns = columns.filter((column) => column.field !== "eventId" && column.field !== "eventName");
|
|
36486
37115
|
filters = filters.filter((filter) => filter.param !== "eventId");
|
|
36487
37116
|
}
|
|
37117
|
+
const showApprovalColumn = key === "products" && requireProductApproval === true || key === "events" && requireEventApproval === true;
|
|
37118
|
+
if (!showApprovalColumn) {
|
|
37119
|
+
columns = columns.filter((column) => column.field !== "approvalStatus");
|
|
37120
|
+
filters = filters.filter((filter) => filter.param !== "approvalStatus");
|
|
37121
|
+
}
|
|
36488
37122
|
if (multiVendorEnabled !== false && !vendorPortal && STORE_VENDOR_RESOURCES.has(key) && key !== "event_products" && !columns.some((c) => c.field === "vendorId")) {
|
|
36489
37123
|
columns = [
|
|
36490
37124
|
VENDOR_COLUMN2,
|
|
@@ -36522,7 +37156,9 @@ function AdminPageResolver({ slug }) {
|
|
|
36522
37156
|
vendorOptions,
|
|
36523
37157
|
vendorPortal,
|
|
36524
37158
|
multiVendorEnabled,
|
|
36525
|
-
eventsEnabled
|
|
37159
|
+
eventsEnabled,
|
|
37160
|
+
requireProductApproval,
|
|
37161
|
+
requireEventApproval
|
|
36526
37162
|
]);
|
|
36527
37163
|
const isContactsWithStore = key === "contacts" && storeEnabled;
|
|
36528
37164
|
const extraListParams = useMemo(() => isContactsWithStore ? {
|
|
@@ -36636,7 +37272,27 @@ function AdminPageResolver({ slug }) {
|
|
|
36636
37272
|
className: "ml-2"
|
|
36637
37273
|
}, "Redirecting\u2026"));
|
|
36638
37274
|
}
|
|
36639
|
-
if (vendorPortal && key === "product_categories") {
|
|
37275
|
+
if (vendorPortal && key === "product_categories" && vendorCanCreateCategories !== true) {
|
|
37276
|
+
router.replace("/admin/products");
|
|
37277
|
+
return /* @__PURE__ */ React26__default.createElement("div", {
|
|
37278
|
+
className: "flex justify-center py-8"
|
|
37279
|
+
}, /* @__PURE__ */ React26__default.createElement("div", {
|
|
37280
|
+
className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
|
|
37281
|
+
}), /* @__PURE__ */ React26__default.createElement("span", {
|
|
37282
|
+
className: "ml-2"
|
|
37283
|
+
}, "Redirecting\u2026"));
|
|
37284
|
+
}
|
|
37285
|
+
if (vendorPortal && key === "collections" && vendorCanCreateCollections !== true) {
|
|
37286
|
+
router.replace("/admin/products");
|
|
37287
|
+
return /* @__PURE__ */ React26__default.createElement("div", {
|
|
37288
|
+
className: "flex justify-center py-8"
|
|
37289
|
+
}, /* @__PURE__ */ React26__default.createElement("div", {
|
|
37290
|
+
className: "animate-spin rounded-full h-6 w-6 border-2 border-gray-300 border-t-gray-600"
|
|
37291
|
+
}), /* @__PURE__ */ React26__default.createElement("span", {
|
|
37292
|
+
className: "ml-2"
|
|
37293
|
+
}, "Redirecting\u2026"));
|
|
37294
|
+
}
|
|
37295
|
+
if (vendorPortal && key === "brands" && vendorCanCreateBrands !== true) {
|
|
36640
37296
|
router.replace("/admin/products");
|
|
36641
37297
|
return /* @__PURE__ */ React26__default.createElement("div", {
|
|
36642
37298
|
className: "flex justify-center py-8"
|