@orion-studios/payload-studio 0.6.0-beta.11 → 0.6.0-beta.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/client.js +2083 -568
- package/dist/admin/client.mjs +2097 -595
- package/dist/admin/index.d.mts +2 -2
- package/dist/admin/index.d.ts +2 -2
- package/dist/admin/index.js +125 -16
- package/dist/admin/index.mjs +1 -1
- package/dist/admin-app/client.js +14 -5
- package/dist/admin-app/client.mjs +1 -1
- package/dist/admin-app/index.d.mts +2 -2
- package/dist/admin-app/index.d.ts +2 -2
- package/dist/admin-app/styles.css +277 -1
- package/dist/admin.css +98 -2
- package/dist/builder-v2/client.d.mts +18 -0
- package/dist/builder-v2/client.d.ts +18 -0
- package/dist/builder-v2/client.js +3301 -0
- package/dist/builder-v2/client.mjs +3176 -0
- package/dist/builder-v2/index.d.mts +242 -0
- package/dist/builder-v2/index.d.ts +242 -0
- package/dist/builder-v2/index.js +805 -0
- package/dist/builder-v2/index.mjs +755 -0
- package/dist/builder-v2/styles.css +2382 -0
- package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
- package/dist/{chunk-T4OH6KI6.mjs → chunk-JC3UV74N.mjs} +125 -16
- package/dist/{chunk-KPIX7OSV.mjs → chunk-NF37A575.mjs} +14 -5
- package/dist/{chunk-XKUTZ7IU.mjs → chunk-NGLIA2OE.mjs} +53 -2
- package/dist/{chunk-OTHERBGX.mjs → chunk-ZADL33R6.mjs} +1 -1
- package/dist/{index-yhpAgqDS.d.ts → index-BV0vEGl6.d.ts} +2 -2
- package/dist/{index-Cv-6qnrw.d.mts → index-D5zrOdyv.d.mts} +3 -1
- package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
- package/dist/{index-Xt3Ep8WV.d.mts → index-DLfPOqYA.d.mts} +2 -2
- package/dist/{index-Crx_MtPw.d.ts → index-Dv-Alx4h.d.ts} +3 -1
- package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +216 -20
- package/dist/index.mjs +4 -4
- package/dist/nextjs/index.js +39 -3
- package/dist/nextjs/index.mjs +2 -2
- package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
- package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
- package/dist/studio-pages/builder.css +66 -5
- package/dist/studio-pages/client.js +618 -73
- package/dist/studio-pages/client.mjs +641 -96
- package/dist/studio-pages/index.d.mts +1 -1
- package/dist/studio-pages/index.d.ts +1 -1
- package/dist/studio-pages/index.js +91 -4
- package/dist/studio-pages/index.mjs +2 -2
- package/package.json +22 -3
package/dist/admin/client.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
SiteFooterPreview,
|
|
10
10
|
adminNavIcons,
|
|
11
11
|
buildAdminPageLinkOptions
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-NF37A575.mjs";
|
|
13
13
|
import "../chunk-ROTPP5CU.mjs";
|
|
14
14
|
import {
|
|
15
15
|
BlockPicker,
|
|
@@ -99,9 +99,9 @@ function Logo({ brandName = "Orion Studio", logoOnDarkUrl, logoUrl } = {}) {
|
|
|
99
99
|
const branding = useSiteBranding(brandName, logoUrl, logoOnDarkUrl);
|
|
100
100
|
const resolvedName = branding.siteName || brandName;
|
|
101
101
|
const resolvedLogo = branding.logoUrl || logoUrl || null;
|
|
102
|
-
const resolvedLogoOnDark = branding.logoOnDarkUrl || logoOnDarkUrl || resolvedLogo;
|
|
102
|
+
const resolvedLogoOnDark = branding.logoOnDarkUrl || logoOnDarkUrl || resolvedLogo || "";
|
|
103
103
|
const hasDarkLogoVariant = Boolean(
|
|
104
|
-
resolvedLogo && resolvedLogoOnDark
|
|
104
|
+
resolvedLogo && resolvedLogoOnDark.trim().length > 0 && resolvedLogoOnDark !== resolvedLogo
|
|
105
105
|
);
|
|
106
106
|
return /* @__PURE__ */ jsxs(
|
|
107
107
|
"div",
|
|
@@ -1273,9 +1273,9 @@ function WelcomeHeader({
|
|
|
1273
1273
|
}
|
|
1274
1274
|
|
|
1275
1275
|
// src/admin/components/studio/AdminStudioNav.tsx
|
|
1276
|
-
import { useMemo } from "react";
|
|
1276
|
+
import { useMemo, useState as useState7 } from "react";
|
|
1277
1277
|
import { usePathname } from "next/navigation";
|
|
1278
|
-
import {
|
|
1278
|
+
import { useAuth } from "@payloadcms/ui";
|
|
1279
1279
|
|
|
1280
1280
|
// src/admin/components/studio/adminPathUtils.ts
|
|
1281
1281
|
import { useEffect as useEffect6, useState as useState6 } from "react";
|
|
@@ -1353,7 +1353,7 @@ var useAdminBasePath = (fallback = DEFAULT_ADMIN_BASE_PATH) => {
|
|
|
1353
1353
|
};
|
|
1354
1354
|
|
|
1355
1355
|
// src/shared/studioSections.ts
|
|
1356
|
-
var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
|
|
1356
|
+
var studioRoles = /* @__PURE__ */ new Set(["admin", "developer", "editor", "client"]);
|
|
1357
1357
|
var studioIcons = new Set(adminNavIcons);
|
|
1358
1358
|
var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1359
1359
|
var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
|
|
@@ -1551,7 +1551,7 @@ var buildStudioNavItems = (props, adminBasePath) => {
|
|
|
1551
1551
|
icon: "tools",
|
|
1552
1552
|
label: "Admin Tools",
|
|
1553
1553
|
matchPrefixes: [toolsPath, resolveAdminPath(adminBasePath, "/collections/users")],
|
|
1554
|
-
roles: ["admin"]
|
|
1554
|
+
roles: ["admin", "developer"]
|
|
1555
1555
|
};
|
|
1556
1556
|
const extensionItems = sections.map((section) => ({
|
|
1557
1557
|
href: resolveAdminPath(adminBasePath, section.href),
|
|
@@ -1648,8 +1648,26 @@ function NavIcon({ sectionID }) {
|
|
|
1648
1648
|
return null;
|
|
1649
1649
|
}
|
|
1650
1650
|
}
|
|
1651
|
+
function LogoutIcon() {
|
|
1652
|
+
const props = {
|
|
1653
|
+
fill: "none",
|
|
1654
|
+
height: iconSize2,
|
|
1655
|
+
stroke: "currentColor",
|
|
1656
|
+
strokeLinecap: "round",
|
|
1657
|
+
strokeLinejoin: "round",
|
|
1658
|
+
strokeWidth: 2,
|
|
1659
|
+
viewBox: "0 0 24 24",
|
|
1660
|
+
width: iconSize2
|
|
1661
|
+
};
|
|
1662
|
+
return /* @__PURE__ */ jsxs11("svg", { ...props, "aria-hidden": "true", children: [
|
|
1663
|
+
/* @__PURE__ */ jsx12("path", { d: "M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4" }),
|
|
1664
|
+
/* @__PURE__ */ jsx12("polyline", { points: "10 17 5 12 10 7" }),
|
|
1665
|
+
/* @__PURE__ */ jsx12("line", { x1: "5", y1: "12", x2: "17", y2: "12" })
|
|
1666
|
+
] });
|
|
1667
|
+
}
|
|
1651
1668
|
function AdminStudioNav(props) {
|
|
1652
1669
|
const { user } = useAuth();
|
|
1670
|
+
const [loggingOut, setLoggingOut] = useState7(false);
|
|
1653
1671
|
const brandName = getPropString(props, "brandName", "Orion Studio");
|
|
1654
1672
|
const logoUrl = getPropString(props, "logoUrl", "");
|
|
1655
1673
|
const compact = getPropBoolean(props, "compact", false);
|
|
@@ -1660,6 +1678,18 @@ function AdminStudioNav(props) {
|
|
|
1660
1678
|
const dashboardPath = adminBasePath;
|
|
1661
1679
|
const userRole = readUserRole(user);
|
|
1662
1680
|
const links = useMemo(() => buildStudioNavItems(props, adminBasePath), [adminBasePath, props]);
|
|
1681
|
+
const logout = async () => {
|
|
1682
|
+
setLoggingOut(true);
|
|
1683
|
+
try {
|
|
1684
|
+
await fetch("/api/users/logout", {
|
|
1685
|
+
credentials: "include",
|
|
1686
|
+
method: "POST"
|
|
1687
|
+
});
|
|
1688
|
+
window.location.href = `${adminBasePath}/login`;
|
|
1689
|
+
} finally {
|
|
1690
|
+
setLoggingOut(false);
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1663
1693
|
if (isStudioShellRoute(pathname, props, adminBasePath)) {
|
|
1664
1694
|
return null;
|
|
1665
1695
|
}
|
|
@@ -1750,7 +1780,38 @@ function AdminStudioNav(props) {
|
|
|
1750
1780
|
/* @__PURE__ */ jsx12("div", { style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem" }, children: "Signed in as" }),
|
|
1751
1781
|
/* @__PURE__ */ jsx12("div", { style: { fontWeight: 800, marginBottom: "0.55rem" }, children: typeof user?.email === "string" ? user.email : "User" })
|
|
1752
1782
|
] }) : null,
|
|
1753
|
-
/* @__PURE__ */
|
|
1783
|
+
/* @__PURE__ */ jsxs11(
|
|
1784
|
+
"button",
|
|
1785
|
+
{
|
|
1786
|
+
"aria-label": "Log out",
|
|
1787
|
+
disabled: loggingOut,
|
|
1788
|
+
onClick: () => void logout(),
|
|
1789
|
+
style: {
|
|
1790
|
+
alignItems: "center",
|
|
1791
|
+
background: "transparent",
|
|
1792
|
+
border: "1px solid var(--theme-elevation-150)",
|
|
1793
|
+
borderRadius: 10,
|
|
1794
|
+
color: "var(--theme-elevation-900)",
|
|
1795
|
+
cursor: loggingOut ? "not-allowed" : "pointer",
|
|
1796
|
+
display: "inline-flex",
|
|
1797
|
+
font: "inherit",
|
|
1798
|
+
fontWeight: 800,
|
|
1799
|
+
gap: compact ? 0 : "0.45rem",
|
|
1800
|
+
justifyContent: "center",
|
|
1801
|
+
minHeight: compact ? 48 : 34,
|
|
1802
|
+
minWidth: compact ? 48 : 0,
|
|
1803
|
+
opacity: loggingOut ? 0.55 : 1,
|
|
1804
|
+
padding: compact ? 0 : "0.4rem 0.62rem",
|
|
1805
|
+
width: compact ? 48 : "auto"
|
|
1806
|
+
},
|
|
1807
|
+
title: "Log out",
|
|
1808
|
+
type: "button",
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsx12(LogoutIcon, {}),
|
|
1811
|
+
!compact ? /* @__PURE__ */ jsx12("span", { children: loggingOut ? "Logging out..." : "Log out" }) : null
|
|
1812
|
+
]
|
|
1813
|
+
}
|
|
1814
|
+
)
|
|
1754
1815
|
]
|
|
1755
1816
|
}
|
|
1756
1817
|
)
|
|
@@ -1840,13 +1901,13 @@ function AdminPage({ title, description, breadcrumbs, actions, children }) {
|
|
|
1840
1901
|
}
|
|
1841
1902
|
|
|
1842
1903
|
// src/admin/components/studio/AdminStudioDashboardClient.tsx
|
|
1843
|
-
import { startTransition, useEffect as useEffect7, useMemo as useMemo3, useState as
|
|
1904
|
+
import { startTransition, useEffect as useEffect7, useMemo as useMemo3, useState as useState8 } from "react";
|
|
1844
1905
|
import Link from "next/link";
|
|
1845
1906
|
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1846
1907
|
var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
1847
|
-
var isRole = (value) => value === "admin" || value === "
|
|
1848
|
-
var canReviewForms = (role) => role === "admin" || role === "editor";
|
|
1849
|
-
var canCreatePages = (role) => role === "admin" || role === "editor";
|
|
1908
|
+
var isRole = (value) => value === "admin" || value === "client" || value === "developer" || value === "editor";
|
|
1909
|
+
var canReviewForms = (role) => role === "admin" || role === "developer" || role === "editor";
|
|
1910
|
+
var canCreatePages = (role) => role === "admin" || role === "developer" || role === "editor";
|
|
1850
1911
|
var canAccess = (role, roles) => {
|
|
1851
1912
|
if (!roles || roles.length === 0) {
|
|
1852
1913
|
return true;
|
|
@@ -2062,7 +2123,7 @@ function AdminStudioDashboardClient({
|
|
|
2062
2123
|
children
|
|
2063
2124
|
}) {
|
|
2064
2125
|
const role = isRole(userRole) ? userRole : void 0;
|
|
2065
|
-
const [state, setState] =
|
|
2126
|
+
const [state, setState] = useState8(
|
|
2066
2127
|
() => formsEnabled && canReviewForms(role) ? {
|
|
2067
2128
|
forms: { status: "loading" },
|
|
2068
2129
|
media: { status: "loading" },
|
|
@@ -2322,7 +2383,7 @@ function AdminStudioDashboardClient({
|
|
|
2322
2383
|
label: "Manage Media",
|
|
2323
2384
|
tone: "ghost"
|
|
2324
2385
|
});
|
|
2325
|
-
if (role === "admin") {
|
|
2386
|
+
if (role === "admin" || role === "developer") {
|
|
2326
2387
|
actions.push({
|
|
2327
2388
|
description: "Manage users, roles, and fallback tools.",
|
|
2328
2389
|
href: toolsPath,
|
|
@@ -2601,7 +2662,7 @@ var buildSectionLinks = (adminBasePath, sections, formsEnabled, globalsBasePath)
|
|
|
2601
2662
|
href: resolveAdminPath2(adminBasePath, "/tools"),
|
|
2602
2663
|
id: "admin-tools",
|
|
2603
2664
|
label: "Admin Tools",
|
|
2604
|
-
roles: ["admin"]
|
|
2665
|
+
roles: ["admin", "developer"]
|
|
2605
2666
|
}
|
|
2606
2667
|
];
|
|
2607
2668
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2667,15 +2728,16 @@ function AdminStudioDashboard(rawProps) {
|
|
|
2667
2728
|
}
|
|
2668
2729
|
|
|
2669
2730
|
// src/admin/components/studio/AdminStudioPagesListView.tsx
|
|
2670
|
-
import { useEffect as
|
|
2731
|
+
import { useEffect as useEffect9, useMemo as useMemo5, useState as useState11 } from "react";
|
|
2671
2732
|
import Link2 from "next/link";
|
|
2733
|
+
import { usePathname as usePathname3 } from "next/navigation";
|
|
2734
|
+
import { useAuth as useAuth4 } from "@payloadcms/ui";
|
|
2735
|
+
|
|
2736
|
+
// src/admin/components/studio/AdminStudioNewPageView.tsx
|
|
2737
|
+
import { useState as useState9 } from "react";
|
|
2672
2738
|
import { useAuth as useAuth3 } from "@payloadcms/ui";
|
|
2673
2739
|
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2674
|
-
var
|
|
2675
|
-
if (!user || typeof user !== "object") return false;
|
|
2676
|
-
const role = user.role;
|
|
2677
|
-
return typeof role === "string" && role === "admin";
|
|
2678
|
-
};
|
|
2740
|
+
var pageTemplates = ["standard", "landing", "services", "contact"];
|
|
2679
2741
|
var getPropString3 = (props, key, fallback) => {
|
|
2680
2742
|
if (!props || typeof props !== "object") return fallback;
|
|
2681
2743
|
const direct = props[key];
|
|
@@ -2687,101 +2749,115 @@ var getPropString3 = (props, key, fallback) => {
|
|
|
2687
2749
|
}
|
|
2688
2750
|
return fallback;
|
|
2689
2751
|
};
|
|
2690
|
-
|
|
2752
|
+
var canManagePages = (user) => {
|
|
2753
|
+
if (!user || typeof user !== "object") return false;
|
|
2754
|
+
const role = user.role;
|
|
2755
|
+
return role === "admin" || role === "developer" || role === "editor";
|
|
2756
|
+
};
|
|
2757
|
+
var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
2758
|
+
function AdminStudioNewPageView(props) {
|
|
2691
2759
|
const { user } = useAuth3();
|
|
2692
|
-
const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
|
|
2693
2760
|
const adminBasePath = useAdminBasePath();
|
|
2694
|
-
const
|
|
2695
|
-
const [
|
|
2696
|
-
const [error, setError] =
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
try {
|
|
2713
|
-
const res = await fetch(apiURL, { credentials: "include" });
|
|
2714
|
-
if (!res.ok) {
|
|
2715
|
-
const body = await res.text();
|
|
2716
|
-
throw new Error(body || "Failed to fetch pages");
|
|
2717
|
-
}
|
|
2718
|
-
const data = await res.json();
|
|
2719
|
-
if (!cancelled) {
|
|
2720
|
-
setDocs(Array.isArray(data.docs) ? data.docs : []);
|
|
2721
|
-
}
|
|
2722
|
-
} catch (err) {
|
|
2723
|
-
if (!cancelled) {
|
|
2724
|
-
setError(err instanceof Error ? err.message : "Failed to fetch pages");
|
|
2725
|
-
}
|
|
2726
|
-
} finally {
|
|
2727
|
-
if (!cancelled) {
|
|
2728
|
-
setLoading(false);
|
|
2729
|
-
}
|
|
2761
|
+
const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
|
|
2762
|
+
const [submitting, setSubmitting] = useState9(false);
|
|
2763
|
+
const [error, setError] = useState9(null);
|
|
2764
|
+
if (!canManagePages(user)) {
|
|
2765
|
+
return /* @__PURE__ */ jsx18(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx18(
|
|
2766
|
+
AdminPage,
|
|
2767
|
+
{
|
|
2768
|
+
breadcrumbs: [
|
|
2769
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
2770
|
+
{ label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
|
|
2771
|
+
{ label: "New Page" }
|
|
2772
|
+
],
|
|
2773
|
+
description: "You do not have access to create pages.",
|
|
2774
|
+
title: "New Page",
|
|
2775
|
+
children: /* @__PURE__ */ jsxs15("div", { className: "orion-admin-card", children: [
|
|
2776
|
+
/* @__PURE__ */ jsx18("strong", { children: "Access denied" }),
|
|
2777
|
+
/* @__PURE__ */ jsx18("span", { children: "This section is restricted to administrator, developer, and editor accounts." })
|
|
2778
|
+
] })
|
|
2730
2779
|
}
|
|
2731
|
-
};
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2780
|
+
) });
|
|
2781
|
+
}
|
|
2782
|
+
const createPage = async (event) => {
|
|
2783
|
+
event.preventDefault();
|
|
2784
|
+
setSubmitting(true);
|
|
2785
|
+
setError(null);
|
|
2786
|
+
try {
|
|
2787
|
+
const formData = new FormData(event.currentTarget);
|
|
2788
|
+
const titleValue = String(formData.get("title") || "").trim();
|
|
2789
|
+
const slugValue = String(formData.get("slug") || "").trim();
|
|
2790
|
+
const templateValue = String(formData.get("template") || "standard").trim();
|
|
2791
|
+
const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
|
|
2792
|
+
const title = titleValue || "Untitled Page";
|
|
2793
|
+
const slug = slugValue || slugify(title) || "untitled-page";
|
|
2794
|
+
const response = await fetch(`/api/${pagesCollectionSlug}`, {
|
|
2795
|
+
body: JSON.stringify({
|
|
2796
|
+
_status: "draft",
|
|
2797
|
+
slug,
|
|
2798
|
+
template,
|
|
2799
|
+
title
|
|
2800
|
+
}),
|
|
2801
|
+
credentials: "include",
|
|
2802
|
+
headers: {
|
|
2803
|
+
"Content-Type": "application/json"
|
|
2804
|
+
},
|
|
2805
|
+
method: "POST"
|
|
2806
|
+
});
|
|
2807
|
+
if (!response.ok) {
|
|
2808
|
+
throw new Error(`Failed to create page (${response.status}).`);
|
|
2809
|
+
}
|
|
2810
|
+
const payload = await response.json();
|
|
2811
|
+
const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
|
|
2812
|
+
if (!id) {
|
|
2813
|
+
throw new Error("Page created but no document ID was returned.");
|
|
2814
|
+
}
|
|
2815
|
+
window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
|
|
2816
|
+
} catch (createError) {
|
|
2817
|
+
setError(createError instanceof Error ? createError.message : "Failed to create page.");
|
|
2818
|
+
} finally {
|
|
2819
|
+
setSubmitting(false);
|
|
2820
|
+
}
|
|
2821
|
+
};
|
|
2822
|
+
return /* @__PURE__ */ jsx18(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx18(
|
|
2738
2823
|
AdminPage,
|
|
2739
2824
|
{
|
|
2740
|
-
actions: isAdmin(user) ? /* @__PURE__ */ jsx18(Link2, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
|
|
2741
2825
|
breadcrumbs: [
|
|
2742
2826
|
{ label: "Dashboard", href: adminBasePath },
|
|
2743
|
-
{ label: "Pages" }
|
|
2827
|
+
{ label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
|
|
2828
|
+
{ label: "New Page" }
|
|
2744
2829
|
],
|
|
2745
|
-
description: "
|
|
2746
|
-
title: "
|
|
2747
|
-
children: [
|
|
2748
|
-
loading ? /* @__PURE__ */ jsx18("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
2830
|
+
description: "Create a new page and open it in the custom editor.",
|
|
2831
|
+
title: "New Page",
|
|
2832
|
+
children: /* @__PURE__ */ jsxs15("form", { className: "orion-admin-form", onSubmit: createPage, children: [
|
|
2749
2833
|
error ? /* @__PURE__ */ jsx18("div", { className: "orion-admin-error", children: error }) : null,
|
|
2750
|
-
/* @__PURE__ */ jsxs15("
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2834
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
2835
|
+
"Title",
|
|
2836
|
+
/* @__PURE__ */ jsx18("input", { name: "title", placeholder: "Services", required: true, type: "text" })
|
|
2837
|
+
] }),
|
|
2838
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
2839
|
+
"Slug",
|
|
2840
|
+
/* @__PURE__ */ jsx18("input", { name: "slug", placeholder: "services", type: "text" })
|
|
2841
|
+
] }),
|
|
2842
|
+
/* @__PURE__ */ jsxs15("label", { children: [
|
|
2843
|
+
"Template",
|
|
2844
|
+
/* @__PURE__ */ jsxs15("select", { defaultValue: "standard", name: "template", children: [
|
|
2845
|
+
/* @__PURE__ */ jsx18("option", { value: "standard", children: "Standard" }),
|
|
2846
|
+
/* @__PURE__ */ jsx18("option", { value: "landing", children: "Landing" }),
|
|
2847
|
+
/* @__PURE__ */ jsx18("option", { value: "contact", children: "Contact" }),
|
|
2848
|
+
/* @__PURE__ */ jsx18("option", { value: "services", children: "Services" })
|
|
2849
|
+
] })
|
|
2850
|
+
] }),
|
|
2851
|
+
/* @__PURE__ */ jsx18("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
|
|
2852
|
+
] })
|
|
2767
2853
|
}
|
|
2768
2854
|
) });
|
|
2769
2855
|
}
|
|
2770
2856
|
|
|
2771
2857
|
// src/admin/components/studio/AdminStudioPageEditView.tsx
|
|
2772
|
-
import { useEffect as
|
|
2773
|
-
import { SetStepNav
|
|
2858
|
+
import { useEffect as useEffect8, useMemo as useMemo4, useRef as useRef3, useState as useState10 } from "react";
|
|
2859
|
+
import { SetStepNav } from "@payloadcms/ui";
|
|
2774
2860
|
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2775
|
-
var isAdmin2 = (user) => {
|
|
2776
|
-
if (!user || typeof user !== "object") return false;
|
|
2777
|
-
const role = user.role;
|
|
2778
|
-
return typeof role === "string" && role === "admin";
|
|
2779
|
-
};
|
|
2780
|
-
var isEditor = (user) => {
|
|
2781
|
-
if (!user || typeof user !== "object") return false;
|
|
2782
|
-
const role = user.role;
|
|
2783
|
-
return typeof role === "string" && role === "editor";
|
|
2784
|
-
};
|
|
2785
2861
|
var getPropString4 = (props, key, fallback) => {
|
|
2786
2862
|
if (!props || typeof props !== "object") return fallback;
|
|
2787
2863
|
const direct = props[key];
|
|
@@ -2809,20 +2885,14 @@ var getPageIDFromPathname = (pathname) => {
|
|
|
2809
2885
|
return pagePart ? decodeURIComponent(pagePart) : null;
|
|
2810
2886
|
};
|
|
2811
2887
|
function AdminStudioPageEditView(props) {
|
|
2812
|
-
const { user } = useAuth4();
|
|
2813
2888
|
const adminBasePath = useAdminBasePath();
|
|
2814
2889
|
const iframeRef = useRef3(null);
|
|
2815
|
-
const [saving, setSaving] = useState9(null);
|
|
2816
|
-
const [dirty, setDirty] = useState9(false);
|
|
2817
|
-
const [hasUnpublishedChanges, setHasUnpublishedChanges] = useState9(false);
|
|
2818
|
-
const [canUndo, setCanUndo] = useState9(false);
|
|
2819
|
-
const [canRedo, setCanRedo] = useState9(false);
|
|
2820
2890
|
const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
|
|
2821
2891
|
const pagesPath = resolveAdminPath(adminBasePath, "/pages");
|
|
2822
|
-
const pageIDFromParams =
|
|
2823
|
-
const [pageID, setPageID] =
|
|
2824
|
-
const [didResolvePathFallback, setDidResolvePathFallback] =
|
|
2825
|
-
|
|
2892
|
+
const pageIDFromParams = useMemo4(() => getParam(props.params, "id"), [props.params]);
|
|
2893
|
+
const [pageID, setPageID] = useState10(pageIDFromParams);
|
|
2894
|
+
const [didResolvePathFallback, setDidResolvePathFallback] = useState10(false);
|
|
2895
|
+
useEffect8(() => {
|
|
2826
2896
|
if (pageIDFromParams) {
|
|
2827
2897
|
setPageID(pageIDFromParams);
|
|
2828
2898
|
setDidResolvePathFallback(true);
|
|
@@ -2833,96 +2903,6 @@ function AdminStudioPageEditView(props) {
|
|
|
2833
2903
|
}
|
|
2834
2904
|
setDidResolvePathFallback(true);
|
|
2835
2905
|
}, [pageIDFromParams]);
|
|
2836
|
-
const canPublish = isAdmin2(user) || isEditor(user);
|
|
2837
|
-
const refreshUnpublishedState = async (id) => {
|
|
2838
|
-
try {
|
|
2839
|
-
const response = await fetch(
|
|
2840
|
-
`/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
|
|
2841
|
-
{
|
|
2842
|
-
credentials: "include"
|
|
2843
|
-
}
|
|
2844
|
-
);
|
|
2845
|
-
if (!response.ok) {
|
|
2846
|
-
return;
|
|
2847
|
-
}
|
|
2848
|
-
const payload = await response.json();
|
|
2849
|
-
const docs = Array.isArray(payload.docs) ? payload.docs : [];
|
|
2850
|
-
let latestDraft = 0;
|
|
2851
|
-
let latestPublished = 0;
|
|
2852
|
-
docs.forEach((doc) => {
|
|
2853
|
-
const status = doc.version?._status;
|
|
2854
|
-
const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
|
|
2855
|
-
if (!Number.isFinite(millis)) {
|
|
2856
|
-
return;
|
|
2857
|
-
}
|
|
2858
|
-
if (status === "draft") {
|
|
2859
|
-
latestDraft = Math.max(latestDraft, millis);
|
|
2860
|
-
}
|
|
2861
|
-
if (status === "published") {
|
|
2862
|
-
latestPublished = Math.max(latestPublished, millis);
|
|
2863
|
-
}
|
|
2864
|
-
});
|
|
2865
|
-
setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
|
|
2866
|
-
} catch {
|
|
2867
|
-
}
|
|
2868
|
-
};
|
|
2869
|
-
useEffect9(() => {
|
|
2870
|
-
if (!pageID) {
|
|
2871
|
-
return;
|
|
2872
|
-
}
|
|
2873
|
-
void refreshUnpublishedState(pageID);
|
|
2874
|
-
}, [pageID]);
|
|
2875
|
-
const requestSave = (status) => {
|
|
2876
|
-
const iframe = iframeRef.current;
|
|
2877
|
-
if (!iframe?.contentWindow) {
|
|
2878
|
-
toast.error("Editor is not ready yet. Please try again.");
|
|
2879
|
-
return;
|
|
2880
|
-
}
|
|
2881
|
-
setSaving(status);
|
|
2882
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
|
|
2883
|
-
};
|
|
2884
|
-
const requestHistoryAction = (type) => {
|
|
2885
|
-
const iframe = iframeRef.current;
|
|
2886
|
-
if (!iframe?.contentWindow) {
|
|
2887
|
-
toast.error("Editor is not ready yet. Please try again.");
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
|
|
2891
|
-
};
|
|
2892
|
-
useEffect9(() => {
|
|
2893
|
-
const onMessage = (event) => {
|
|
2894
|
-
const data = event.data;
|
|
2895
|
-
if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
|
|
2896
|
-
return;
|
|
2897
|
-
}
|
|
2898
|
-
if (data.type === "dirty-state") {
|
|
2899
|
-
setDirty(Boolean(data.dirty));
|
|
2900
|
-
return;
|
|
2901
|
-
}
|
|
2902
|
-
if (data.type === "history-state") {
|
|
2903
|
-
setCanUndo(Boolean(data.canUndo));
|
|
2904
|
-
setCanRedo(Boolean(data.canRedo));
|
|
2905
|
-
return;
|
|
2906
|
-
}
|
|
2907
|
-
if (data.type === "save-result") {
|
|
2908
|
-
setSaving(null);
|
|
2909
|
-
if (data.ok) {
|
|
2910
|
-
if (data.status === "draft") {
|
|
2911
|
-
setHasUnpublishedChanges(true);
|
|
2912
|
-
} else if (data.status === "published") {
|
|
2913
|
-
setHasUnpublishedChanges(false);
|
|
2914
|
-
} else if (pageID) {
|
|
2915
|
-
void refreshUnpublishedState(pageID);
|
|
2916
|
-
}
|
|
2917
|
-
toast.success(typeof data.message === "string" ? data.message : "Saved.");
|
|
2918
|
-
} else {
|
|
2919
|
-
toast.error(typeof data.message === "string" ? data.message : "Save failed.");
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
};
|
|
2923
|
-
window.addEventListener("message", onMessage);
|
|
2924
|
-
return () => window.removeEventListener("message", onMessage);
|
|
2925
|
-
}, []);
|
|
2926
2906
|
if (!pageID && !didResolvePathFallback) {
|
|
2927
2907
|
return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment4, { children: [
|
|
2928
2908
|
/* @__PURE__ */ jsx19(
|
|
@@ -2963,155 +2943,25 @@ function AdminStudioPageEditView(props) {
|
|
|
2963
2943
|
]
|
|
2964
2944
|
}
|
|
2965
2945
|
),
|
|
2966
|
-
/* @__PURE__ */
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
gap: "0.6rem",
|
|
2976
|
-
justifyContent: "space-between",
|
|
2977
|
-
padding: "0.65rem 0.9rem",
|
|
2978
|
-
position: "sticky",
|
|
2979
|
-
top: 0,
|
|
2980
|
-
zIndex: 20
|
|
2981
|
-
},
|
|
2982
|
-
children: [
|
|
2983
|
-
/* @__PURE__ */ jsxs16("div", { style: { minWidth: 0 }, children: [
|
|
2984
|
-
/* @__PURE__ */ jsx19("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
|
|
2985
|
-
/* @__PURE__ */ jsxs16(
|
|
2986
|
-
"div",
|
|
2987
|
-
{
|
|
2988
|
-
style: {
|
|
2989
|
-
color: "var(--theme-elevation-600)",
|
|
2990
|
-
fontSize: "0.85rem",
|
|
2991
|
-
overflow: "hidden",
|
|
2992
|
-
textOverflow: "ellipsis"
|
|
2993
|
-
},
|
|
2994
|
-
children: [
|
|
2995
|
-
"Editing: ",
|
|
2996
|
-
pageID
|
|
2997
|
-
]
|
|
2998
|
-
}
|
|
2999
|
-
)
|
|
3000
|
-
] }),
|
|
3001
|
-
/* @__PURE__ */ jsxs16("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
|
|
3002
|
-
/* @__PURE__ */ jsx19("div", { style: { color: dirty ? "var(--theme-elevation-900)" : "var(--theme-elevation-600)", fontSize: "0.85rem", fontWeight: 700 }, children: dirty ? "Unsaved changes" : "All changes saved" }),
|
|
3003
|
-
/* @__PURE__ */ jsx19(
|
|
3004
|
-
"div",
|
|
3005
|
-
{
|
|
3006
|
-
style: {
|
|
3007
|
-
background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
|
|
3008
|
-
border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
|
|
3009
|
-
borderRadius: 999,
|
|
3010
|
-
color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
|
|
3011
|
-
fontSize: "0.75rem",
|
|
3012
|
-
fontWeight: 800,
|
|
3013
|
-
padding: "0.2rem 0.55rem",
|
|
3014
|
-
whiteSpace: "nowrap"
|
|
3015
|
-
},
|
|
3016
|
-
title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
|
|
3017
|
-
children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
|
|
3018
|
-
}
|
|
3019
|
-
),
|
|
3020
|
-
/* @__PURE__ */ jsx19(
|
|
3021
|
-
"button",
|
|
3022
|
-
{
|
|
3023
|
-
disabled: !canUndo,
|
|
3024
|
-
onClick: () => requestHistoryAction("undo"),
|
|
3025
|
-
style: {
|
|
3026
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
3027
|
-
borderRadius: 12,
|
|
3028
|
-
cursor: canUndo ? "pointer" : "not-allowed",
|
|
3029
|
-
fontWeight: 800,
|
|
3030
|
-
padding: "0.5rem 0.65rem"
|
|
3031
|
-
},
|
|
3032
|
-
type: "button",
|
|
3033
|
-
children: "Undo"
|
|
3034
|
-
}
|
|
3035
|
-
),
|
|
3036
|
-
/* @__PURE__ */ jsx19(
|
|
3037
|
-
"button",
|
|
3038
|
-
{
|
|
3039
|
-
disabled: !canRedo,
|
|
3040
|
-
onClick: () => requestHistoryAction("redo"),
|
|
3041
|
-
style: {
|
|
3042
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
3043
|
-
borderRadius: 12,
|
|
3044
|
-
cursor: canRedo ? "pointer" : "not-allowed",
|
|
3045
|
-
fontWeight: 800,
|
|
3046
|
-
padding: "0.5rem 0.65rem"
|
|
3047
|
-
},
|
|
3048
|
-
type: "button",
|
|
3049
|
-
children: "Redo"
|
|
3050
|
-
}
|
|
3051
|
-
),
|
|
3052
|
-
/* @__PURE__ */ jsx19(
|
|
3053
|
-
"button",
|
|
3054
|
-
{
|
|
3055
|
-
disabled: saving !== null,
|
|
3056
|
-
onClick: () => requestSave("draft"),
|
|
3057
|
-
style: {
|
|
3058
|
-
border: "1px solid var(--theme-elevation-300)",
|
|
3059
|
-
borderRadius: 12,
|
|
3060
|
-
cursor: saving ? "not-allowed" : "pointer",
|
|
3061
|
-
fontWeight: 800,
|
|
3062
|
-
padding: "0.5rem 0.75rem"
|
|
3063
|
-
},
|
|
3064
|
-
type: "button",
|
|
3065
|
-
children: saving === "draft" ? "Saving\u2026" : "Save Draft"
|
|
3066
|
-
}
|
|
3067
|
-
),
|
|
3068
|
-
/* @__PURE__ */ jsx19(
|
|
3069
|
-
"button",
|
|
3070
|
-
{
|
|
3071
|
-
disabled: !canPublish || saving !== null,
|
|
3072
|
-
onClick: () => requestSave("published"),
|
|
3073
|
-
style: {
|
|
3074
|
-
background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
|
|
3075
|
-
border: "none",
|
|
3076
|
-
borderRadius: 12,
|
|
3077
|
-
color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
|
|
3078
|
-
cursor: !canPublish || saving ? "not-allowed" : "pointer",
|
|
3079
|
-
fontWeight: 900,
|
|
3080
|
-
padding: "0.5rem 0.75rem"
|
|
3081
|
-
},
|
|
3082
|
-
type: "button",
|
|
3083
|
-
title: !canPublish ? "You do not have publish permissions." : void 0,
|
|
3084
|
-
children: saving === "published" ? "Publishing\u2026" : "Publish"
|
|
3085
|
-
}
|
|
3086
|
-
)
|
|
3087
|
-
] })
|
|
3088
|
-
]
|
|
3089
|
-
}
|
|
3090
|
-
),
|
|
3091
|
-
/* @__PURE__ */ jsx19(
|
|
3092
|
-
"iframe",
|
|
3093
|
-
{
|
|
3094
|
-
ref: iframeRef,
|
|
3095
|
-
src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
|
|
3096
|
-
style: { border: "none", height: "100%", width: "100%" },
|
|
3097
|
-
title: "Page Builder",
|
|
3098
|
-
onLoad: () => {
|
|
3099
|
-
const iframe = iframeRef.current;
|
|
3100
|
-
if (!iframe?.contentWindow) return;
|
|
3101
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
|
|
3102
|
-
iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
|
|
3103
|
-
}
|
|
3104
|
-
}
|
|
3105
|
-
)
|
|
3106
|
-
] })
|
|
2946
|
+
/* @__PURE__ */ jsx19("div", { style: { height: "100dvh", overflow: "hidden" }, children: /* @__PURE__ */ jsx19(
|
|
2947
|
+
"iframe",
|
|
2948
|
+
{
|
|
2949
|
+
ref: iframeRef,
|
|
2950
|
+
src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
|
|
2951
|
+
style: { border: "none", height: "100%", width: "100%" },
|
|
2952
|
+
title: "Page Builder"
|
|
2953
|
+
}
|
|
2954
|
+
) })
|
|
3107
2955
|
] }) });
|
|
3108
2956
|
}
|
|
3109
2957
|
|
|
3110
|
-
// src/admin/components/studio/
|
|
3111
|
-
import { useState as useState10 } from "react";
|
|
3112
|
-
import { useAuth as useAuth5 } from "@payloadcms/ui";
|
|
2958
|
+
// src/admin/components/studio/AdminStudioPagesListView.tsx
|
|
3113
2959
|
import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3114
|
-
var
|
|
2960
|
+
var hasAdminAccess = (user) => {
|
|
2961
|
+
if (!user || typeof user !== "object") return false;
|
|
2962
|
+
const role = user.role;
|
|
2963
|
+
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
2964
|
+
};
|
|
3115
2965
|
var getPropString5 = (props, key, fallback) => {
|
|
3116
2966
|
if (!props || typeof props !== "object") return fallback;
|
|
3117
2967
|
const direct = props[key];
|
|
@@ -3123,107 +2973,98 @@ var getPropString5 = (props, key, fallback) => {
|
|
|
3123
2973
|
}
|
|
3124
2974
|
return fallback;
|
|
3125
2975
|
};
|
|
3126
|
-
|
|
3127
|
-
if (!user || typeof user !== "object") return false;
|
|
3128
|
-
const role = user.role;
|
|
3129
|
-
return role === "admin" || role === "editor";
|
|
3130
|
-
};
|
|
3131
|
-
var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
|
|
3132
|
-
function AdminStudioNewPageView(props) {
|
|
3133
|
-
const { user } = useAuth5();
|
|
2976
|
+
function AdminStudioPagesListView(props) {
|
|
3134
2977
|
const adminBasePath = useAdminBasePath();
|
|
3135
|
-
const
|
|
3136
|
-
const
|
|
3137
|
-
const
|
|
3138
|
-
if (
|
|
3139
|
-
return /* @__PURE__ */ jsx20(
|
|
3140
|
-
AdminPage,
|
|
3141
|
-
{
|
|
3142
|
-
breadcrumbs: [
|
|
3143
|
-
{ label: "Dashboard", href: adminBasePath },
|
|
3144
|
-
{ label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
|
|
3145
|
-
{ label: "New Page" }
|
|
3146
|
-
],
|
|
3147
|
-
description: "You do not have access to create pages.",
|
|
3148
|
-
title: "New Page",
|
|
3149
|
-
children: /* @__PURE__ */ jsxs17("div", { className: "orion-admin-card", children: [
|
|
3150
|
-
/* @__PURE__ */ jsx20("strong", { children: "Access denied" }),
|
|
3151
|
-
/* @__PURE__ */ jsx20("span", { children: "This section is restricted to administrator and editor accounts." })
|
|
3152
|
-
] })
|
|
3153
|
-
}
|
|
3154
|
-
) });
|
|
2978
|
+
const pathname = usePathname3();
|
|
2979
|
+
const pagesPath = resolveAdminPath(adminBasePath, "/pages");
|
|
2980
|
+
const nestedPagePath = pathname && pathname.startsWith(`${pagesPath}/`) ? pathname.slice(`${pagesPath}/`.length).split("/")[0] : "";
|
|
2981
|
+
if (nestedPagePath === "new") {
|
|
2982
|
+
return /* @__PURE__ */ jsx20(AdminStudioNewPageView, { ...props });
|
|
3155
2983
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
2984
|
+
if (nestedPagePath) {
|
|
2985
|
+
return /* @__PURE__ */ jsx20(AdminStudioPageEditView, { ...props });
|
|
2986
|
+
}
|
|
2987
|
+
return /* @__PURE__ */ jsx20(AdminStudioPagesIndexView, { ...props, adminBasePath });
|
|
2988
|
+
}
|
|
2989
|
+
function AdminStudioPagesIndexView({
|
|
2990
|
+
adminBasePath,
|
|
2991
|
+
...props
|
|
2992
|
+
}) {
|
|
2993
|
+
const { user } = useAuth4();
|
|
2994
|
+
const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
|
|
2995
|
+
const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
|
|
2996
|
+
const [loading, setLoading] = useState11(true);
|
|
2997
|
+
const [error, setError] = useState11(null);
|
|
2998
|
+
const [docs, setDocs] = useState11([]);
|
|
2999
|
+
const apiURL = useMemo5(() => {
|
|
3000
|
+
const params = new URLSearchParams({
|
|
3001
|
+
depth: "0",
|
|
3002
|
+
limit: "100",
|
|
3003
|
+
sort: "-updatedAt",
|
|
3004
|
+
draft: "true"
|
|
3005
|
+
});
|
|
3006
|
+
return `/api/${pagesCollectionSlug}?${params.toString()}`;
|
|
3007
|
+
}, [pagesCollectionSlug]);
|
|
3008
|
+
useEffect9(() => {
|
|
3009
|
+
let cancelled = false;
|
|
3010
|
+
const run = async () => {
|
|
3011
|
+
setLoading(true);
|
|
3012
|
+
setError(null);
|
|
3013
|
+
try {
|
|
3014
|
+
const res = await fetch(apiURL, { credentials: "include" });
|
|
3015
|
+
if (!res.ok) {
|
|
3016
|
+
const body = await res.text();
|
|
3017
|
+
throw new Error(body || "Failed to fetch pages");
|
|
3018
|
+
}
|
|
3019
|
+
const data = await res.json();
|
|
3020
|
+
if (!cancelled) {
|
|
3021
|
+
setDocs(Array.isArray(data.docs) ? data.docs : []);
|
|
3022
|
+
}
|
|
3023
|
+
} catch (err) {
|
|
3024
|
+
if (!cancelled) {
|
|
3025
|
+
setError(err instanceof Error ? err.message : "Failed to fetch pages");
|
|
3026
|
+
}
|
|
3027
|
+
} finally {
|
|
3028
|
+
if (!cancelled) {
|
|
3029
|
+
setLoading(false);
|
|
3030
|
+
}
|
|
3188
3031
|
}
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
return /* @__PURE__ */ jsx20(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx20(
|
|
3032
|
+
};
|
|
3033
|
+
void run();
|
|
3034
|
+
return () => {
|
|
3035
|
+
cancelled = true;
|
|
3036
|
+
};
|
|
3037
|
+
}, [apiURL]);
|
|
3038
|
+
return /* @__PURE__ */ jsx20(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs17(
|
|
3197
3039
|
AdminPage,
|
|
3198
3040
|
{
|
|
3041
|
+
actions: hasAdminAccess(user) ? /* @__PURE__ */ jsx20(Link2, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
|
|
3199
3042
|
breadcrumbs: [
|
|
3200
3043
|
{ label: "Dashboard", href: adminBasePath },
|
|
3201
|
-
{ label: "Pages"
|
|
3202
|
-
{ label: "New Page" }
|
|
3044
|
+
{ label: "Pages" }
|
|
3203
3045
|
],
|
|
3204
|
-
description: "
|
|
3205
|
-
title: "
|
|
3206
|
-
children:
|
|
3046
|
+
description: "Open a page to edit it in the inline custom builder.",
|
|
3047
|
+
title: "Pages",
|
|
3048
|
+
children: [
|
|
3049
|
+
loading ? /* @__PURE__ */ jsx20("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
3207
3050
|
error ? /* @__PURE__ */ jsx20("div", { className: "orion-admin-error", children: error }) : null,
|
|
3208
|
-
/* @__PURE__ */ jsxs17("
|
|
3209
|
-
"
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
/* @__PURE__ */ jsx20("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
|
|
3226
|
-
] })
|
|
3051
|
+
/* @__PURE__ */ jsxs17("div", { className: "orion-admin-list", children: [
|
|
3052
|
+
!loading && !error && docs.length === 0 ? /* @__PURE__ */ jsxs17("div", { className: "orion-admin-card", children: [
|
|
3053
|
+
/* @__PURE__ */ jsx20("strong", { children: "No pages yet" }),
|
|
3054
|
+
/* @__PURE__ */ jsx20("span", { children: "Create the first page to start building content." })
|
|
3055
|
+
] }) : null,
|
|
3056
|
+
docs.map((doc) => {
|
|
3057
|
+
const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
|
|
3058
|
+
if (!id) return null;
|
|
3059
|
+
const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
|
|
3060
|
+
const status = typeof doc._status === "string" ? doc._status : "draft";
|
|
3061
|
+
return /* @__PURE__ */ jsxs17(Link2, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
|
|
3062
|
+
/* @__PURE__ */ jsx20("div", { children: /* @__PURE__ */ jsx20("strong", { children: title }) }),
|
|
3063
|
+
/* @__PURE__ */ jsx20("span", { className: "orion-admin-pill", children: status })
|
|
3064
|
+
] }, id);
|
|
3065
|
+
})
|
|
3066
|
+
] })
|
|
3067
|
+
]
|
|
3227
3068
|
}
|
|
3228
3069
|
) });
|
|
3229
3070
|
}
|
|
@@ -3276,7 +3117,7 @@ function AdminStudioGlobalsView(props) {
|
|
|
3276
3117
|
}
|
|
3277
3118
|
|
|
3278
3119
|
// src/admin/components/studio/AdminStudioSiteSettingsGlobalView.tsx
|
|
3279
|
-
import { useEffect as useEffect10, useMemo as useMemo6, useState as
|
|
3120
|
+
import { useEffect as useEffect10, useMemo as useMemo6, useState as useState12 } from "react";
|
|
3280
3121
|
import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
3281
3122
|
var getPropString6 = (props, key, fallback) => {
|
|
3282
3123
|
if (!props || typeof props !== "object") return fallback;
|
|
@@ -3362,12 +3203,12 @@ function AdminStudioSiteSettingsGlobalView(props) {
|
|
|
3362
3203
|
const mediaCollectionSlug = getPropString6(props, "mediaCollectionSlug", "media");
|
|
3363
3204
|
const adminBasePath = useAdminBasePath();
|
|
3364
3205
|
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
3365
|
-
const [loading, setLoading] =
|
|
3366
|
-
const [saving, setSaving] =
|
|
3367
|
-
const [error, setError] =
|
|
3368
|
-
const [savedMessage, setSavedMessage] =
|
|
3369
|
-
const [globalData, setGlobalData] =
|
|
3370
|
-
const [mediaOptions, setMediaOptions] =
|
|
3206
|
+
const [loading, setLoading] = useState12(true);
|
|
3207
|
+
const [saving, setSaving] = useState12(false);
|
|
3208
|
+
const [error, setError] = useState12(null);
|
|
3209
|
+
const [savedMessage, setSavedMessage] = useState12(null);
|
|
3210
|
+
const [globalData, setGlobalData] = useState12({});
|
|
3211
|
+
const [mediaOptions, setMediaOptions] = useState12([]);
|
|
3371
3212
|
useEffect10(() => {
|
|
3372
3213
|
let cancelled = false;
|
|
3373
3214
|
const run = async () => {
|
|
@@ -3652,7 +3493,7 @@ function AdminStudioSiteSettingsGlobalView(props) {
|
|
|
3652
3493
|
}
|
|
3653
3494
|
|
|
3654
3495
|
// src/admin/components/studio/AdminStudioSocialMediaGlobalView.tsx
|
|
3655
|
-
import { useEffect as useEffect11, useMemo as useMemo7, useState as
|
|
3496
|
+
import { useEffect as useEffect11, useMemo as useMemo7, useState as useState13 } from "react";
|
|
3656
3497
|
|
|
3657
3498
|
// src/shared/socialMedia.ts
|
|
3658
3499
|
var SOCIAL_MEDIA_PLATFORM_LABELS = {
|
|
@@ -3789,11 +3630,11 @@ function AdminStudioSocialMediaGlobalView(props) {
|
|
|
3789
3630
|
const globalsBasePath = getPropString7(props, "globalsBasePath", "/globals");
|
|
3790
3631
|
const adminBasePath = useAdminBasePath();
|
|
3791
3632
|
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
3792
|
-
const [loading, setLoading] =
|
|
3793
|
-
const [saving, setSaving] =
|
|
3794
|
-
const [error, setError] =
|
|
3795
|
-
const [savedMessage, setSavedMessage] =
|
|
3796
|
-
const [globalData, setGlobalData] =
|
|
3633
|
+
const [loading, setLoading] = useState13(true);
|
|
3634
|
+
const [saving, setSaving] = useState13(false);
|
|
3635
|
+
const [error, setError] = useState13(null);
|
|
3636
|
+
const [savedMessage, setSavedMessage] = useState13(null);
|
|
3637
|
+
const [globalData, setGlobalData] = useState13({});
|
|
3797
3638
|
useEffect11(() => {
|
|
3798
3639
|
let cancelled = false;
|
|
3799
3640
|
const run = async () => {
|
|
@@ -3933,7 +3774,7 @@ function AdminStudioSocialMediaGlobalView(props) {
|
|
|
3933
3774
|
}
|
|
3934
3775
|
|
|
3935
3776
|
// src/admin/components/studio/AdminStudioHeaderGlobalView.tsx
|
|
3936
|
-
import { useEffect as useEffect12, useMemo as useMemo8, useState as
|
|
3777
|
+
import { useEffect as useEffect12, useMemo as useMemo8, useState as useState14 } from "react";
|
|
3937
3778
|
import { SetStepNav as SetStepNav2 } from "@payloadcms/ui";
|
|
3938
3779
|
|
|
3939
3780
|
// src/nextjs/utilities/socialMedia.ts
|
|
@@ -4029,15 +3870,15 @@ function AdminStudioHeaderGlobalView(props) {
|
|
|
4029
3870
|
const adminBasePath = useAdminBasePath();
|
|
4030
3871
|
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
4031
3872
|
const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
|
|
4032
|
-
const [loading, setLoading] =
|
|
4033
|
-
const [saving, setSaving] =
|
|
4034
|
-
const [error, setError] =
|
|
4035
|
-
const [savedMessage, setSavedMessage] =
|
|
4036
|
-
const [initialItems, setInitialItems] =
|
|
4037
|
-
const [liveItems, setLiveItems] =
|
|
4038
|
-
const [pages, setPages] =
|
|
4039
|
-
const [siteSettings, setSiteSettings] =
|
|
4040
|
-
const [socialMedia, setSocialMedia] =
|
|
3873
|
+
const [loading, setLoading] = useState14(true);
|
|
3874
|
+
const [saving, setSaving] = useState14(false);
|
|
3875
|
+
const [error, setError] = useState14(null);
|
|
3876
|
+
const [savedMessage, setSavedMessage] = useState14(null);
|
|
3877
|
+
const [initialItems, setInitialItems] = useState14([]);
|
|
3878
|
+
const [liveItems, setLiveItems] = useState14([]);
|
|
3879
|
+
const [pages, setPages] = useState14([]);
|
|
3880
|
+
const [siteSettings, setSiteSettings] = useState14({});
|
|
3881
|
+
const [socialMedia, setSocialMedia] = useState14({});
|
|
4041
3882
|
useEffect12(() => {
|
|
4042
3883
|
let cancelled = false;
|
|
4043
3884
|
const run = async () => {
|
|
@@ -4204,7 +4045,7 @@ function AdminStudioHeaderGlobalView(props) {
|
|
|
4204
4045
|
}
|
|
4205
4046
|
|
|
4206
4047
|
// src/admin/components/studio/AdminStudioFooterGlobalView.tsx
|
|
4207
|
-
import { useEffect as useEffect13, useMemo as useMemo9, useState as
|
|
4048
|
+
import { useEffect as useEffect13, useMemo as useMemo9, useState as useState15 } from "react";
|
|
4208
4049
|
import { SetStepNav as SetStepNav3 } from "@payloadcms/ui";
|
|
4209
4050
|
import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4210
4051
|
var getPropString9 = (props, key, fallback) => {
|
|
@@ -4312,17 +4153,17 @@ function AdminStudioFooterGlobalView(props) {
|
|
|
4312
4153
|
const adminBasePath = useAdminBasePath();
|
|
4313
4154
|
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
4314
4155
|
const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
|
|
4315
|
-
const [loading, setLoading] =
|
|
4316
|
-
const [saving, setSaving] =
|
|
4317
|
-
const [error, setError] =
|
|
4318
|
-
const [savedMessage, setSavedMessage] =
|
|
4319
|
-
const [doc, setDoc] =
|
|
4156
|
+
const [loading, setLoading] = useState15(true);
|
|
4157
|
+
const [saving, setSaving] = useState15(false);
|
|
4158
|
+
const [error, setError] = useState15(null);
|
|
4159
|
+
const [savedMessage, setSavedMessage] = useState15(null);
|
|
4160
|
+
const [doc, setDoc] = useState15({
|
|
4320
4161
|
contactEmail: "",
|
|
4321
4162
|
contactPhone: "",
|
|
4322
4163
|
copyright: ""
|
|
4323
4164
|
});
|
|
4324
|
-
const [siteSettings, setSiteSettings] =
|
|
4325
|
-
const [socialMedia, setSocialMedia] =
|
|
4165
|
+
const [siteSettings, setSiteSettings] = useState15({});
|
|
4166
|
+
const [socialMedia, setSocialMedia] = useState15({});
|
|
4326
4167
|
useEffect13(() => {
|
|
4327
4168
|
let cancelled = false;
|
|
4328
4169
|
const run = async () => {
|
|
@@ -4579,7 +4420,7 @@ function AdminStudioFooterGlobalView(props) {
|
|
|
4579
4420
|
}
|
|
4580
4421
|
|
|
4581
4422
|
// src/admin/components/studio/AdminStudioContactFormView.tsx
|
|
4582
|
-
import { useEffect as useEffect14, useMemo as useMemo10, useState as
|
|
4423
|
+
import { useEffect as useEffect14, useMemo as useMemo10, useState as useState16 } from "react";
|
|
4583
4424
|
import { SetStepNav as SetStepNav4 } from "@payloadcms/ui";
|
|
4584
4425
|
import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
4585
4426
|
var defaultDoc = {
|
|
@@ -4670,11 +4511,11 @@ function AdminStudioContactFormView(props) {
|
|
|
4670
4511
|
const adminBasePath = useAdminBasePath();
|
|
4671
4512
|
const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
|
|
4672
4513
|
const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
|
|
4673
|
-
const [doc, setDoc] =
|
|
4674
|
-
const [error, setError] =
|
|
4675
|
-
const [isLoading, setIsLoading] =
|
|
4676
|
-
const [isSaving, setIsSaving] =
|
|
4677
|
-
const [savedMessage, setSavedMessage] =
|
|
4514
|
+
const [doc, setDoc] = useState16(defaultDoc);
|
|
4515
|
+
const [error, setError] = useState16(null);
|
|
4516
|
+
const [isLoading, setIsLoading] = useState16(true);
|
|
4517
|
+
const [isSaving, setIsSaving] = useState16(false);
|
|
4518
|
+
const [savedMessage, setSavedMessage] = useState16(null);
|
|
4678
4519
|
useEffect14(() => {
|
|
4679
4520
|
let mounted = true;
|
|
4680
4521
|
const load = async () => {
|
|
@@ -4905,7 +4746,7 @@ function AdminStudioContactFormView(props) {
|
|
|
4905
4746
|
}
|
|
4906
4747
|
|
|
4907
4748
|
// src/admin/components/studio/AdminStudioMediaView.tsx
|
|
4908
|
-
import { useEffect as useEffect15, useMemo as useMemo11, useState as
|
|
4749
|
+
import { useEffect as useEffect15, useMemo as useMemo11, useState as useState17 } from "react";
|
|
4909
4750
|
import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
4910
4751
|
var MEDIA_LIBRARY_SYNC_EVENT = "orion-media-library-updated";
|
|
4911
4752
|
var getPropString11 = (props, key, fallback) => {
|
|
@@ -4922,9 +4763,9 @@ var getPropString11 = (props, key, fallback) => {
|
|
|
4922
4763
|
function AdminStudioMediaView(props) {
|
|
4923
4764
|
const mediaCollectionSlug = getPropString11(props, "mediaCollectionSlug", "media");
|
|
4924
4765
|
const adminBasePath = useAdminBasePath();
|
|
4925
|
-
const [docs, setDocs] =
|
|
4926
|
-
const [loading, setLoading] =
|
|
4927
|
-
const [error, setError] =
|
|
4766
|
+
const [docs, setDocs] = useState17([]);
|
|
4767
|
+
const [loading, setLoading] = useState17(true);
|
|
4768
|
+
const [error, setError] = useState17(null);
|
|
4928
4769
|
const apiURL = useMemo11(() => {
|
|
4929
4770
|
const params = new URLSearchParams({
|
|
4930
4771
|
depth: "0",
|
|
@@ -5014,7 +4855,7 @@ function AdminStudioMediaView(props) {
|
|
|
5014
4855
|
}
|
|
5015
4856
|
|
|
5016
4857
|
// src/admin/components/studio/AdminStudioMediaItemView.tsx
|
|
5017
|
-
import { useEffect as useEffect16, useMemo as useMemo12, useState as
|
|
4858
|
+
import { useEffect as useEffect16, useMemo as useMemo12, useState as useState18 } from "react";
|
|
5018
4859
|
import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
5019
4860
|
var getPropString12 = (props, key, fallback) => {
|
|
5020
4861
|
if (!props || typeof props !== "object") return fallback;
|
|
@@ -5046,11 +4887,11 @@ function AdminStudioMediaItemView(props) {
|
|
|
5046
4887
|
const adminBasePath = useAdminBasePath();
|
|
5047
4888
|
const mediaPath = resolveAdminPath(adminBasePath, "/media");
|
|
5048
4889
|
const mediaIDFromParams = useMemo12(() => getParam2(props.params, "id"), [props.params]);
|
|
5049
|
-
const [mediaID, setMediaID] =
|
|
5050
|
-
const [doc, setDoc] =
|
|
5051
|
-
const [loading, setLoading] =
|
|
5052
|
-
const [error, setError] =
|
|
5053
|
-
const [savedMessage, setSavedMessage] =
|
|
4890
|
+
const [mediaID, setMediaID] = useState18(mediaIDFromParams);
|
|
4891
|
+
const [doc, setDoc] = useState18(null);
|
|
4892
|
+
const [loading, setLoading] = useState18(true);
|
|
4893
|
+
const [error, setError] = useState18(null);
|
|
4894
|
+
const [savedMessage, setSavedMessage] = useState18(null);
|
|
5054
4895
|
useEffect16(() => {
|
|
5055
4896
|
if (mediaIDFromParams) {
|
|
5056
4897
|
setMediaID(mediaIDFromParams);
|
|
@@ -5162,8 +5003,8 @@ function AdminStudioMediaItemView(props) {
|
|
|
5162
5003
|
|
|
5163
5004
|
// src/admin/components/studio/AdminStudioFormsView.tsx
|
|
5164
5005
|
import Link3 from "next/link";
|
|
5165
|
-
import { useEffect as useEffect17, useMemo as useMemo13, useState as
|
|
5166
|
-
import { useAuth as
|
|
5006
|
+
import { useEffect as useEffect17, useMemo as useMemo13, useState as useState19 } from "react";
|
|
5007
|
+
import { useAuth as useAuth5 } from "@payloadcms/ui";
|
|
5167
5008
|
import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
5168
5009
|
var FORM_TONES = [
|
|
5169
5010
|
{
|
|
@@ -5205,17 +5046,17 @@ var FORM_TONE_OVERRIDES = {
|
|
|
5205
5046
|
var IDENTITY_KEYS = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
|
|
5206
5047
|
var RESPONSE_FIELD_PREVIEW_LIMIT = 3;
|
|
5207
5048
|
var RESPONSE_SCROLL_THRESHOLD = 3;
|
|
5208
|
-
var
|
|
5049
|
+
var hasAdminAccess2 = (user) => {
|
|
5209
5050
|
if (!user || typeof user !== "object") return false;
|
|
5210
5051
|
const role = user.role;
|
|
5211
|
-
return typeof role === "string" && role === "admin";
|
|
5052
|
+
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
5212
5053
|
};
|
|
5213
|
-
var
|
|
5054
|
+
var isEditor = (user) => {
|
|
5214
5055
|
if (!user || typeof user !== "object") return false;
|
|
5215
5056
|
const role = user.role;
|
|
5216
5057
|
return typeof role === "string" && role === "editor";
|
|
5217
5058
|
};
|
|
5218
|
-
var canReviewForms2 = (user) =>
|
|
5059
|
+
var canReviewForms2 = (user) => hasAdminAccess2(user) || isEditor(user);
|
|
5219
5060
|
var getPropString13 = (props, key, fallback) => {
|
|
5220
5061
|
if (!props || typeof props !== "object") return fallback;
|
|
5221
5062
|
const direct = props[key];
|
|
@@ -5381,25 +5222,21 @@ var renderEmptyMessage = (message) => /* @__PURE__ */ jsxs26("div", { className:
|
|
|
5381
5222
|
/* @__PURE__ */ jsx29("span", { children: message })
|
|
5382
5223
|
] });
|
|
5383
5224
|
function AdminStudioFormsView(props) {
|
|
5384
|
-
const { user } =
|
|
5225
|
+
const { user } = useAuth5();
|
|
5385
5226
|
const formsCollectionSlug = getPropString13(props, "formsCollectionSlug", "forms");
|
|
5386
5227
|
const formSubmissionsCollectionSlug = getPropString13(
|
|
5387
5228
|
props,
|
|
5388
5229
|
"formSubmissionsCollectionSlug",
|
|
5389
5230
|
"form-submissions"
|
|
5390
5231
|
);
|
|
5391
|
-
const formUploadsCollectionSlug = getPropString13(props, "formUploadsCollectionSlug", "form-uploads");
|
|
5392
5232
|
const adminBasePath = useAdminBasePath();
|
|
5393
|
-
const
|
|
5394
|
-
const
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
);
|
|
5398
|
-
const
|
|
5399
|
-
const [
|
|
5400
|
-
const [submissions, setSubmissions] = useState18([]);
|
|
5401
|
-
const [loading, setLoading] = useState18(true);
|
|
5402
|
-
const [error, setError] = useState18(null);
|
|
5233
|
+
const studioFormsPath = resolveAdminPath(adminBasePath, "/forms");
|
|
5234
|
+
const studioSubmissionsPath = resolveAdminPath(adminBasePath, "/forms/submissions");
|
|
5235
|
+
const studioUploadsPath = resolveAdminPath(adminBasePath, "/forms/uploads");
|
|
5236
|
+
const [forms, setForms] = useState19([]);
|
|
5237
|
+
const [submissions, setSubmissions] = useState19([]);
|
|
5238
|
+
const [loading, setLoading] = useState19(true);
|
|
5239
|
+
const [error, setError] = useState19(null);
|
|
5403
5240
|
useEffect17(() => {
|
|
5404
5241
|
if (!canReviewForms2(user)) {
|
|
5405
5242
|
return;
|
|
@@ -5555,7 +5392,7 @@ function AdminStudioFormsView(props) {
|
|
|
5555
5392
|
Link3,
|
|
5556
5393
|
{
|
|
5557
5394
|
className: "orion-admin-action-button orion-admin-action-button--soft",
|
|
5558
|
-
href: `${
|
|
5395
|
+
href: `${studioFormsPath}/${id}`,
|
|
5559
5396
|
children: "Open Form"
|
|
5560
5397
|
}
|
|
5561
5398
|
)
|
|
@@ -5657,7 +5494,7 @@ function AdminStudioFormsView(props) {
|
|
|
5657
5494
|
Link3,
|
|
5658
5495
|
{
|
|
5659
5496
|
className: "orion-admin-upload-chip",
|
|
5660
|
-
href: `${
|
|
5497
|
+
href: `${studioUploadsPath}/${uploadID}`,
|
|
5661
5498
|
children: uploadLabel
|
|
5662
5499
|
},
|
|
5663
5500
|
uploadID
|
|
@@ -5674,7 +5511,7 @@ function AdminStudioFormsView(props) {
|
|
|
5674
5511
|
Link3,
|
|
5675
5512
|
{
|
|
5676
5513
|
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
5677
|
-
href: `${
|
|
5514
|
+
href: `${studioSubmissionsPath}/${submissionID}`,
|
|
5678
5515
|
children: "Open"
|
|
5679
5516
|
}
|
|
5680
5517
|
)
|
|
@@ -5694,39 +5531,1665 @@ function AdminStudioFormsView(props) {
|
|
|
5694
5531
|
) });
|
|
5695
5532
|
}
|
|
5696
5533
|
|
|
5697
|
-
// src/admin/components/studio/
|
|
5698
|
-
import
|
|
5699
|
-
import {
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
var
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5534
|
+
// src/admin/components/studio/AdminStudioFormDetailView.tsx
|
|
5535
|
+
import Link4 from "next/link";
|
|
5536
|
+
import { useEffect as useEffect18, useMemo as useMemo14, useState as useState20 } from "react";
|
|
5537
|
+
|
|
5538
|
+
// src/admin/components/studio/formsStudioShared.ts
|
|
5539
|
+
var FORM_TONES2 = [
|
|
5540
|
+
{
|
|
5541
|
+
accent: "var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent)))",
|
|
5542
|
+
accentBorder: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 24%, transparent)",
|
|
5543
|
+
accentMist: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 12%, transparent)",
|
|
5544
|
+
accentSoft: "color-mix(in srgb, var(--orion-cms-tone-1, var(--orion-cms-accent, var(--orion-admin-accent))) 7%, transparent)"
|
|
5545
|
+
},
|
|
5546
|
+
{
|
|
5547
|
+
accent: "var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent)))",
|
|
5548
|
+
accentBorder: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 24%, transparent)",
|
|
5549
|
+
accentMist: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 13%, transparent)",
|
|
5550
|
+
accentSoft: "color-mix(in srgb, var(--orion-cms-tone-2, var(--brand-secondary, var(--orion-admin-accent))) 8%, transparent)"
|
|
5551
|
+
},
|
|
5552
|
+
{
|
|
5553
|
+
accent: "var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b))",
|
|
5554
|
+
accentBorder: "color-mix(in srgb, var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b)) 24%, transparent)",
|
|
5555
|
+
accentMist: "color-mix(in srgb, var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b)) 12%, transparent)",
|
|
5556
|
+
accentSoft: "color-mix(in srgb, var(--orion-cms-tone-3, color-mix(in srgb, var(--orion-cms-accent, var(--orion-admin-accent)) 72%, #5f816b)) 8%, transparent)"
|
|
5557
|
+
},
|
|
5558
|
+
{
|
|
5559
|
+
accent: "var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e))",
|
|
5560
|
+
accentBorder: "color-mix(in srgb, var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e)) 24%, transparent)",
|
|
5561
|
+
accentMist: "color-mix(in srgb, var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e)) 13%, transparent)",
|
|
5562
|
+
accentSoft: "color-mix(in srgb, var(--orion-cms-tone-4, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 72%, #7a652e)) 8%, transparent)"
|
|
5563
|
+
},
|
|
5564
|
+
{
|
|
5565
|
+
accent: "var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40))",
|
|
5566
|
+
accentBorder: "color-mix(in srgb, var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40)) 24%, transparent)",
|
|
5567
|
+
accentMist: "color-mix(in srgb, var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40)) 13%, transparent)",
|
|
5568
|
+
accentSoft: "color-mix(in srgb, var(--orion-cms-tone-5, color-mix(in srgb, var(--brand-secondary, var(--orion-admin-accent)) 68%, #8d4a40)) 8%, transparent)"
|
|
5569
|
+
}
|
|
5570
|
+
];
|
|
5571
|
+
var FORM_TONE_OVERRIDES2 = {
|
|
5572
|
+
"basket-request": FORM_TONES2[1],
|
|
5573
|
+
contact: FORM_TONES2[2],
|
|
5574
|
+
"vendor-inquiry": FORM_TONES2[0]
|
|
5706
5575
|
};
|
|
5707
|
-
var
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
const
|
|
5712
|
-
|
|
5713
|
-
const
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5576
|
+
var IDENTITY_KEYS2 = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
|
|
5577
|
+
var RESPONSE_FIELD_PREVIEW_LIMIT2 = 3;
|
|
5578
|
+
var getPropString14 = (props, key, fallback) => {
|
|
5579
|
+
if (!props || typeof props !== "object") return fallback;
|
|
5580
|
+
const direct = props[key];
|
|
5581
|
+
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
5582
|
+
const clientProps = props.clientProps;
|
|
5583
|
+
if (clientProps && typeof clientProps === "object") {
|
|
5584
|
+
const nested = clientProps[key];
|
|
5585
|
+
if (typeof nested === "string" && nested.length > 0) return nested;
|
|
5586
|
+
}
|
|
5587
|
+
return fallback;
|
|
5588
|
+
};
|
|
5589
|
+
var getParam3 = (params, key) => {
|
|
5590
|
+
if (!params || typeof params !== "object") return null;
|
|
5591
|
+
const value = params[key];
|
|
5592
|
+
if (typeof value === "string") return value;
|
|
5593
|
+
if (Array.isArray(value) && typeof value[0] === "string") return value[0];
|
|
5594
|
+
return null;
|
|
5595
|
+
};
|
|
5596
|
+
var getIDFromPathname = (pathname, marker) => {
|
|
5597
|
+
const markerIndex = pathname.indexOf(marker);
|
|
5598
|
+
if (markerIndex < 0) return null;
|
|
5599
|
+
const id = pathname.slice(markerIndex + marker.length).split("/")[0];
|
|
5600
|
+
return id ? decodeURIComponent(id) : null;
|
|
5601
|
+
};
|
|
5602
|
+
var formatDate2 = (value) => {
|
|
5603
|
+
if (typeof value !== "string" || value.length === 0) return "Unknown date";
|
|
5604
|
+
const date = new Date(value);
|
|
5605
|
+
if (Number.isNaN(date.getTime())) return value;
|
|
5606
|
+
return date.toLocaleString();
|
|
5607
|
+
};
|
|
5608
|
+
var formatFileSize2 = (value) => {
|
|
5609
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return null;
|
|
5610
|
+
if (value < 1024) return `${value} B`;
|
|
5611
|
+
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
|
|
5612
|
+
return `${(value / (1024 * 1024)).toFixed(1)} MB`;
|
|
5613
|
+
};
|
|
5614
|
+
var getFieldCount2 = (form) => Array.isArray(form.steps) ? form.steps.reduce((count, step) => {
|
|
5615
|
+
if (!step || typeof step !== "object") return count;
|
|
5616
|
+
const fields = step.fields;
|
|
5617
|
+
return count + (Array.isArray(fields) ? fields.length : 0);
|
|
5618
|
+
}, 0) : 0;
|
|
5619
|
+
var getFormID3 = (value) => {
|
|
5620
|
+
if (typeof value === "string" || typeof value === "number") return String(value);
|
|
5621
|
+
if (value && typeof value === "object") {
|
|
5622
|
+
const id = value.id;
|
|
5623
|
+
if (typeof id === "string" || typeof id === "number") return String(id);
|
|
5624
|
+
}
|
|
5625
|
+
return "";
|
|
5626
|
+
};
|
|
5627
|
+
var getUploads2 = (value) => Array.isArray(value) ? value.map((entry) => {
|
|
5628
|
+
if (typeof entry === "string" || typeof entry === "number") {
|
|
5629
|
+
return { id: entry };
|
|
5630
|
+
}
|
|
5631
|
+
return entry && typeof entry === "object" ? entry : null;
|
|
5632
|
+
}).filter((entry) => Boolean(entry)) : [];
|
|
5633
|
+
var getNameAndEmail2 = (data) => {
|
|
5634
|
+
if (!data || typeof data !== "object") return {};
|
|
5635
|
+
const record = data;
|
|
5636
|
+
const email = typeof record.email === "string" ? record.email : typeof record.contactEmail === "string" ? record.contactEmail : void 0;
|
|
5637
|
+
const firstName = typeof record.firstName === "string" ? record.firstName : void 0;
|
|
5638
|
+
const lastName = typeof record.lastName === "string" ? record.lastName : void 0;
|
|
5639
|
+
const fallbackName = typeof record.name === "string" ? record.name : void 0;
|
|
5640
|
+
const joinedName = [firstName, lastName].filter(Boolean).join(" ").trim();
|
|
5641
|
+
return {
|
|
5642
|
+
...email ? { email } : {},
|
|
5643
|
+
...joinedName ? { name: joinedName } : fallbackName ? { name: fallbackName } : {}
|
|
5644
|
+
};
|
|
5645
|
+
};
|
|
5646
|
+
var humanizeKey2 = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (char) => char.toUpperCase());
|
|
5647
|
+
var buildFieldLabelMap2 = (form) => {
|
|
5648
|
+
const labels = /* @__PURE__ */ new Map();
|
|
5649
|
+
for (const step of Array.isArray(form.steps) ? form.steps : []) {
|
|
5650
|
+
const fields = step && typeof step === "object" ? step.fields : null;
|
|
5651
|
+
for (const field of Array.isArray(fields) ? fields : []) {
|
|
5652
|
+
const name = field && typeof field === "object" && typeof field.name === "string" ? field.name.trim() : "";
|
|
5653
|
+
const label = field && typeof field === "object" && typeof field.label === "string" ? field.label.trim() : "";
|
|
5654
|
+
if (name) {
|
|
5655
|
+
labels.set(name, label || humanizeKey2(name));
|
|
5656
|
+
}
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
5659
|
+
return labels;
|
|
5660
|
+
};
|
|
5661
|
+
var truncateText2 = (value, maxLength = 64) => {
|
|
5662
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
5663
|
+
if (normalized.length <= maxLength) return normalized;
|
|
5664
|
+
return `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
|
|
5665
|
+
};
|
|
5666
|
+
var formatPreviewValue2 = (value) => {
|
|
5667
|
+
if (value === null || value === void 0) return null;
|
|
5668
|
+
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
5669
|
+
if (typeof value === "number") return String(value);
|
|
5670
|
+
if (typeof value === "string") {
|
|
5671
|
+
const trimmed = value.trim();
|
|
5672
|
+
return trimmed ? truncateText2(trimmed, 72) : null;
|
|
5673
|
+
}
|
|
5674
|
+
if (Array.isArray(value)) {
|
|
5675
|
+
const joined = value.map((entry) => String(entry).trim()).filter(Boolean).join(", ");
|
|
5676
|
+
return joined ? truncateText2(joined, 72) : null;
|
|
5677
|
+
}
|
|
5678
|
+
if (typeof value === "object") {
|
|
5679
|
+
return truncateText2(JSON.stringify(value), 72);
|
|
5680
|
+
}
|
|
5681
|
+
return truncateText2(String(value), 72);
|
|
5682
|
+
};
|
|
5683
|
+
var getPreviewFields2 = (data, fieldLabels) => {
|
|
5684
|
+
if (!data || typeof data !== "object") return [];
|
|
5685
|
+
return Object.entries(data).filter(([key]) => !IDENTITY_KEYS2.has(key)).map(([key, value]) => {
|
|
5686
|
+
const formatted = formatPreviewValue2(value);
|
|
5687
|
+
if (!formatted) return null;
|
|
5688
|
+
return {
|
|
5689
|
+
label: fieldLabels.get(key) || humanizeKey2(key),
|
|
5690
|
+
value: formatted
|
|
5691
|
+
};
|
|
5692
|
+
}).filter((entry) => Boolean(entry)).slice(0, RESPONSE_FIELD_PREVIEW_LIMIT2);
|
|
5693
|
+
};
|
|
5694
|
+
var getInitials2 = (...values) => {
|
|
5695
|
+
const source = values.find((value) => typeof value === "string" && value.trim().length > 0);
|
|
5696
|
+
if (!source) return "FM";
|
|
5697
|
+
const cleaned = source.replace(/[^a-z0-9]+/gi, " ").trim();
|
|
5698
|
+
if (!cleaned) return "FM";
|
|
5699
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
5700
|
+
if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
|
|
5701
|
+
return `${parts[0][0] || ""}${parts[1][0] || ""}`.toUpperCase();
|
|
5702
|
+
};
|
|
5703
|
+
var getHash2 = (value) => {
|
|
5704
|
+
let hash = 0;
|
|
5705
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
5706
|
+
hash = hash * 31 + value.charCodeAt(index) >>> 0;
|
|
5707
|
+
}
|
|
5708
|
+
return hash;
|
|
5709
|
+
};
|
|
5710
|
+
var normalizeToneKey2 = (value) => value?.trim().toLowerCase() || "";
|
|
5711
|
+
var getFormTone2 = (slug, fallbackSeed) => {
|
|
5712
|
+
const normalizedSlug = normalizeToneKey2(slug);
|
|
5713
|
+
if (normalizedSlug && FORM_TONE_OVERRIDES2[normalizedSlug]) {
|
|
5714
|
+
return FORM_TONE_OVERRIDES2[normalizedSlug];
|
|
5715
|
+
}
|
|
5716
|
+
const normalizedSeed = normalizeToneKey2(fallbackSeed);
|
|
5717
|
+
if (normalizedSeed && FORM_TONE_OVERRIDES2[normalizedSeed]) {
|
|
5718
|
+
return FORM_TONE_OVERRIDES2[normalizedSeed];
|
|
5719
|
+
}
|
|
5720
|
+
return FORM_TONES2[getHash2(slug || fallbackSeed) % FORM_TONES2.length];
|
|
5721
|
+
};
|
|
5722
|
+
var getFormToneStyle2 = (slug, fallbackSeed) => {
|
|
5723
|
+
const tone = getFormTone2(slug, fallbackSeed);
|
|
5724
|
+
return {
|
|
5725
|
+
["--form-accent"]: tone.accent,
|
|
5726
|
+
["--form-accent-border"]: tone.accentBorder,
|
|
5727
|
+
["--form-accent-mist"]: tone.accentMist,
|
|
5728
|
+
["--form-accent-soft"]: tone.accentSoft
|
|
5729
|
+
};
|
|
5730
|
+
};
|
|
5731
|
+
var getFormTitle2 = (value) => {
|
|
5732
|
+
if (value && typeof value === "object" && typeof value.title === "string") {
|
|
5733
|
+
const title = value.title.trim();
|
|
5734
|
+
if (title.length > 0) return title;
|
|
5735
|
+
}
|
|
5736
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
5737
|
+
return value;
|
|
5738
|
+
}
|
|
5739
|
+
return "Untitled Form";
|
|
5740
|
+
};
|
|
5741
|
+
|
|
5742
|
+
// src/admin/components/studio/AdminStudioFormDetailView.tsx
|
|
5743
|
+
import { Fragment as Fragment5, jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
5744
|
+
var getNonEmptyText = (value, fallback = "") => typeof value === "string" && value.trim().length > 0 ? value : fallback;
|
|
5745
|
+
var normalizeSteps = (value) => {
|
|
5746
|
+
if (!Array.isArray(value)) {
|
|
5747
|
+
return [];
|
|
5748
|
+
}
|
|
5749
|
+
return value.map((step) => step && typeof step === "object" && !Array.isArray(step) ? step : {});
|
|
5750
|
+
};
|
|
5751
|
+
var normalizeFormResponse = (value) => {
|
|
5752
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5753
|
+
return {};
|
|
5754
|
+
}
|
|
5755
|
+
const record = value;
|
|
5756
|
+
const nestedDoc = record.doc;
|
|
5757
|
+
if (nestedDoc && typeof nestedDoc === "object" && !Array.isArray(nestedDoc)) {
|
|
5758
|
+
return nestedDoc;
|
|
5759
|
+
}
|
|
5760
|
+
return record;
|
|
5761
|
+
};
|
|
5762
|
+
var toEditorState = (doc) => {
|
|
5763
|
+
const emails = doc.emails && typeof doc.emails === "object" ? doc.emails : null;
|
|
5764
|
+
const adminRecipients = Array.isArray(emails?.adminRecipients) ? emails?.adminRecipients.map(
|
|
5765
|
+
(entry) => entry && typeof entry === "object" && typeof entry.email === "string" ? entry.email.trim() : ""
|
|
5766
|
+
).filter(Boolean) : [];
|
|
5767
|
+
return {
|
|
5768
|
+
adminRecipientsText: adminRecipients.join("\n"),
|
|
5769
|
+
adminSubject: getNonEmptyText(emails?.adminSubject),
|
|
5770
|
+
confirmationHeading: getNonEmptyText(emails?.confirmationHeading),
|
|
5771
|
+
confirmationMessage: getNonEmptyText(emails?.confirmationMessage),
|
|
5772
|
+
confirmationSubject: getNonEmptyText(emails?.confirmationSubject),
|
|
5773
|
+
sendAdmin: emails?.sendAdmin !== false,
|
|
5774
|
+
sendConfirmation: emails?.sendConfirmation !== false,
|
|
5775
|
+
slug: getNonEmptyText(doc.slug),
|
|
5776
|
+
steps: normalizeSteps(doc.steps),
|
|
5777
|
+
submitLabel: getNonEmptyText(doc.submitLabel, "Submit"),
|
|
5778
|
+
successMessage: getNonEmptyText(doc.successMessage),
|
|
5779
|
+
title: getNonEmptyText(doc.title, "Untitled Form")
|
|
5780
|
+
};
|
|
5781
|
+
};
|
|
5782
|
+
var checkboxLabelStyle = {
|
|
5783
|
+
alignItems: "center",
|
|
5784
|
+
display: "flex",
|
|
5785
|
+
gap: "0.6rem"
|
|
5786
|
+
};
|
|
5787
|
+
var sectionGridStyle = {
|
|
5788
|
+
display: "grid",
|
|
5789
|
+
gap: "1rem",
|
|
5790
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
|
|
5791
|
+
};
|
|
5792
|
+
var fieldTypeOptions = [
|
|
5793
|
+
"text",
|
|
5794
|
+
"textarea",
|
|
5795
|
+
"email",
|
|
5796
|
+
"phone",
|
|
5797
|
+
"url",
|
|
5798
|
+
"select",
|
|
5799
|
+
"radio",
|
|
5800
|
+
"checkbox",
|
|
5801
|
+
"checkbox-group",
|
|
5802
|
+
"date",
|
|
5803
|
+
"file"
|
|
5804
|
+
];
|
|
5805
|
+
var getFields = (step) => Array.isArray(step.fields) ? step.fields.map(
|
|
5806
|
+
(field) => field && typeof field === "object" && !Array.isArray(field) ? field : {}
|
|
5807
|
+
) : [];
|
|
5808
|
+
var toOptionsText = (value) => Array.isArray(value) ? value.map((entry) => {
|
|
5809
|
+
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
|
|
5810
|
+
const record = entry;
|
|
5811
|
+
const label = typeof record.label === "string" ? record.label : "";
|
|
5812
|
+
const optionValue = typeof record.value === "string" ? record.value : label;
|
|
5813
|
+
return label && optionValue && label !== optionValue ? `${label} | ${optionValue}` : label || optionValue;
|
|
5814
|
+
}
|
|
5815
|
+
return typeof entry === "string" ? entry : "";
|
|
5816
|
+
}).filter(Boolean).join("\n") : "";
|
|
5817
|
+
var fromOptionsText = (value) => value.split("\n").map((entry) => entry.trim()).filter(Boolean).map((entry) => {
|
|
5818
|
+
const [label, optionValue] = entry.split("|").map((part) => part.trim());
|
|
5819
|
+
return {
|
|
5820
|
+
label,
|
|
5821
|
+
value: optionValue || label
|
|
5822
|
+
};
|
|
5823
|
+
});
|
|
5824
|
+
var slugifyFieldName = (value) => value.trim().replace(/[^a-z0-9]+/gi, " ").trim().replace(/\s+([a-z0-9])/gi, (_, char) => char.toUpperCase()).replace(/^./, (char) => char.toLowerCase());
|
|
5825
|
+
var blankField = () => ({
|
|
5826
|
+
label: "New field",
|
|
5827
|
+
name: "newField",
|
|
5828
|
+
required: false,
|
|
5829
|
+
type: "text"
|
|
5830
|
+
});
|
|
5831
|
+
var blankStep = () => ({
|
|
5832
|
+
fields: [blankField()],
|
|
5833
|
+
title: "New step"
|
|
5834
|
+
});
|
|
5835
|
+
var getStepTitle = (step, stepIndex) => getNonEmptyText(step.title, `Step ${stepIndex + 1}`);
|
|
5836
|
+
var getFieldLabel = (field, fieldIndex) => getNonEmptyText(field.label, getNonEmptyText(field.name, `Field ${fieldIndex + 1}`));
|
|
5837
|
+
var formatFieldTypeLabel = (value) => getNonEmptyText(value, "text").replace(/-/g, " ").replace(/^./, (char) => char.toUpperCase());
|
|
5838
|
+
var getStepDestination = (stepIndex, stepCount) => {
|
|
5839
|
+
if (stepIndex < stepCount - 1) {
|
|
5840
|
+
return `Next: Step ${stepIndex + 2}`;
|
|
5841
|
+
}
|
|
5842
|
+
return "Then: Submit form";
|
|
5843
|
+
};
|
|
5844
|
+
var moveItem = (items, fromIndex, toIndex) => {
|
|
5845
|
+
if (toIndex < 0 || toIndex >= items.length) {
|
|
5846
|
+
return items;
|
|
5847
|
+
}
|
|
5848
|
+
const nextItems = [...items];
|
|
5849
|
+
const [item] = nextItems.splice(fromIndex, 1);
|
|
5850
|
+
nextItems.splice(toIndex, 0, item);
|
|
5851
|
+
return nextItems;
|
|
5852
|
+
};
|
|
5853
|
+
function getFormIDFromPathname(pathname) {
|
|
5854
|
+
const marker = "/forms/";
|
|
5855
|
+
const raw = getIDFromPathname(pathname, marker);
|
|
5856
|
+
if (!raw || raw === "submissions" || raw === "uploads") {
|
|
5857
|
+
return null;
|
|
5858
|
+
}
|
|
5859
|
+
return raw;
|
|
5860
|
+
}
|
|
5861
|
+
function AdminStudioFormDetailView(props) {
|
|
5862
|
+
const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
|
|
5863
|
+
const formSubmissionsCollectionSlug = getPropString14(
|
|
5864
|
+
props,
|
|
5865
|
+
"formSubmissionsCollectionSlug",
|
|
5866
|
+
"form-submissions"
|
|
5867
|
+
);
|
|
5868
|
+
const adminBasePath = useAdminBasePath();
|
|
5869
|
+
const formsPath = resolveAdminPath(adminBasePath, "/forms");
|
|
5870
|
+
const formIDFromParams = useMemo14(() => getParam3(props.params, "id"), [props.params]);
|
|
5871
|
+
const [formID, setFormID] = useState20(formIDFromParams);
|
|
5872
|
+
const [didResolvePathFallback, setDidResolvePathFallback] = useState20(false);
|
|
5873
|
+
const [doc, setDoc] = useState20(null);
|
|
5874
|
+
const [submissions, setSubmissions] = useState20([]);
|
|
5875
|
+
const [editorState, setEditorState] = useState20(null);
|
|
5876
|
+
const [loading, setLoading] = useState20(true);
|
|
5877
|
+
const [error, setError] = useState20(null);
|
|
5878
|
+
const [saving, setSaving] = useState20(false);
|
|
5879
|
+
const [savedMessage, setSavedMessage] = useState20(null);
|
|
5880
|
+
useEffect18(() => {
|
|
5881
|
+
if (formIDFromParams) {
|
|
5882
|
+
setFormID(formIDFromParams);
|
|
5883
|
+
setDidResolvePathFallback(true);
|
|
5884
|
+
return;
|
|
5885
|
+
}
|
|
5886
|
+
if (typeof window !== "undefined") {
|
|
5887
|
+
setFormID(getFormIDFromPathname(window.location.pathname));
|
|
5888
|
+
}
|
|
5889
|
+
setDidResolvePathFallback(true);
|
|
5890
|
+
}, [formIDFromParams]);
|
|
5891
|
+
const loadDoc = async (id) => {
|
|
5892
|
+
setLoading(true);
|
|
5893
|
+
setError(null);
|
|
5894
|
+
try {
|
|
5895
|
+
const submissionsParams = new URLSearchParams({
|
|
5896
|
+
depth: "1",
|
|
5897
|
+
limit: "25",
|
|
5898
|
+
sort: "-submittedAt"
|
|
5899
|
+
});
|
|
5900
|
+
submissionsParams.set("where[form][equals]", id);
|
|
5901
|
+
const [formResponse, submissionsResponse] = await Promise.all([
|
|
5902
|
+
fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
|
|
5903
|
+
credentials: "include"
|
|
5904
|
+
}),
|
|
5905
|
+
fetch(`/api/${formSubmissionsCollectionSlug}?${submissionsParams.toString()}`, {
|
|
5906
|
+
credentials: "include"
|
|
5907
|
+
})
|
|
5908
|
+
]);
|
|
5909
|
+
if (!formResponse.ok) {
|
|
5910
|
+
throw new Error(`Failed to load form (${formResponse.status}).`);
|
|
5911
|
+
}
|
|
5912
|
+
if (!submissionsResponse.ok) {
|
|
5913
|
+
throw new Error(`Failed to load submissions (${submissionsResponse.status}).`);
|
|
5914
|
+
}
|
|
5915
|
+
const nextDoc = normalizeFormResponse(await formResponse.json());
|
|
5916
|
+
const submissionsPayload = await submissionsResponse.json();
|
|
5917
|
+
const nextSubmissions = Array.isArray(submissionsPayload.docs) ? submissionsPayload.docs : [];
|
|
5918
|
+
setDoc(nextDoc);
|
|
5919
|
+
setEditorState(toEditorState(nextDoc));
|
|
5920
|
+
setSubmissions(nextSubmissions);
|
|
5921
|
+
} catch (loadError) {
|
|
5922
|
+
setError(loadError instanceof Error ? loadError.message : "Failed to load form.");
|
|
5923
|
+
setDoc(null);
|
|
5924
|
+
setEditorState(null);
|
|
5925
|
+
setSubmissions([]);
|
|
5926
|
+
} finally {
|
|
5927
|
+
setLoading(false);
|
|
5928
|
+
}
|
|
5929
|
+
};
|
|
5930
|
+
useEffect18(() => {
|
|
5931
|
+
if (!formID) {
|
|
5932
|
+
return;
|
|
5933
|
+
}
|
|
5934
|
+
void loadDoc(formID);
|
|
5935
|
+
}, [formID, formsCollectionSlug, formSubmissionsCollectionSlug]);
|
|
5936
|
+
const save = async (event) => {
|
|
5937
|
+
event.preventDefault();
|
|
5938
|
+
if (!formID || !editorState) {
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
setSaving(true);
|
|
5942
|
+
setError(null);
|
|
5943
|
+
setSavedMessage(null);
|
|
5944
|
+
try {
|
|
5945
|
+
const payload = {
|
|
5946
|
+
emails: {
|
|
5947
|
+
adminRecipients: editorState.adminRecipientsText.split("\n").map((value) => value.trim()).filter(Boolean).map((email) => ({ email })),
|
|
5948
|
+
adminSubject: editorState.adminSubject.trim(),
|
|
5949
|
+
confirmationHeading: editorState.confirmationHeading.trim(),
|
|
5950
|
+
confirmationMessage: editorState.confirmationMessage,
|
|
5951
|
+
confirmationSubject: editorState.confirmationSubject.trim(),
|
|
5952
|
+
sendAdmin: editorState.sendAdmin,
|
|
5953
|
+
sendConfirmation: editorState.sendConfirmation
|
|
5954
|
+
},
|
|
5955
|
+
slug: editorState.slug.trim(),
|
|
5956
|
+
steps: editorState.steps,
|
|
5957
|
+
submitLabel: editorState.submitLabel.trim(),
|
|
5958
|
+
successMessage: editorState.successMessage,
|
|
5959
|
+
title: editorState.title.trim()
|
|
5960
|
+
};
|
|
5961
|
+
const response = await fetch(`/api/${formsCollectionSlug}/${encodeURIComponent(formID)}`, {
|
|
5962
|
+
body: JSON.stringify(payload),
|
|
5963
|
+
credentials: "include",
|
|
5964
|
+
headers: {
|
|
5965
|
+
"Content-Type": "application/json"
|
|
5966
|
+
},
|
|
5967
|
+
method: "PATCH"
|
|
5968
|
+
});
|
|
5969
|
+
if (!response.ok) {
|
|
5970
|
+
throw new Error(`Failed to save form (${response.status}).`);
|
|
5971
|
+
}
|
|
5972
|
+
const nextDoc = normalizeFormResponse(await response.json());
|
|
5973
|
+
setDoc(nextDoc);
|
|
5974
|
+
setEditorState(toEditorState(nextDoc));
|
|
5975
|
+
setSavedMessage("Saved.");
|
|
5976
|
+
} catch (saveError) {
|
|
5977
|
+
setError(saveError instanceof Error ? saveError.message : "Failed to save form.");
|
|
5978
|
+
} finally {
|
|
5979
|
+
setSaving(false);
|
|
5980
|
+
}
|
|
5981
|
+
};
|
|
5982
|
+
if (!formID && !didResolvePathFallback) {
|
|
5983
|
+
return /* @__PURE__ */ jsx30(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx30(
|
|
5984
|
+
AdminPage,
|
|
5985
|
+
{
|
|
5986
|
+
breadcrumbs: [
|
|
5987
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
5988
|
+
{ label: "Forms", href: formsPath },
|
|
5989
|
+
{ label: "Form" }
|
|
5990
|
+
],
|
|
5991
|
+
description: "Loading form workspace...",
|
|
5992
|
+
title: "Form",
|
|
5993
|
+
children: /* @__PURE__ */ jsx30(Fragment5, {})
|
|
5994
|
+
}
|
|
5995
|
+
) });
|
|
5996
|
+
}
|
|
5997
|
+
const title = doc && typeof doc.title === "string" && doc.title.trim().length > 0 ? doc.title : "Form";
|
|
5998
|
+
const slug = doc && typeof doc.slug === "string" ? doc.slug : "";
|
|
5999
|
+
const toneStyle = getFormToneStyle2(slug, title || formID || "form");
|
|
6000
|
+
const fieldLabels = doc ? buildFieldLabelMap2(doc) : /* @__PURE__ */ new Map();
|
|
6001
|
+
const latestSubmission = submissions[0];
|
|
6002
|
+
const stepCount = editorState?.steps.length || 0;
|
|
6003
|
+
const fieldCount = editorState ? editorState.steps.reduce((count, step) => count + getFields(step).length, 0) : doc ? getFieldCount2(doc) : 0;
|
|
6004
|
+
const updateStep = (stepIndex, patch) => {
|
|
6005
|
+
setEditorState(
|
|
6006
|
+
(current) => current ? {
|
|
6007
|
+
...current,
|
|
6008
|
+
steps: current.steps.map(
|
|
6009
|
+
(step, index) => index === stepIndex ? { ...step, ...patch } : step
|
|
6010
|
+
)
|
|
6011
|
+
} : current
|
|
6012
|
+
);
|
|
6013
|
+
};
|
|
6014
|
+
const updateField = (stepIndex, fieldIndex, patch) => {
|
|
6015
|
+
setEditorState((current) => {
|
|
6016
|
+
if (!current) return current;
|
|
6017
|
+
return {
|
|
6018
|
+
...current,
|
|
6019
|
+
steps: current.steps.map((step, index) => {
|
|
6020
|
+
if (index !== stepIndex) return step;
|
|
6021
|
+
const fields = getFields(step).map(
|
|
6022
|
+
(field, currentFieldIndex) => currentFieldIndex === fieldIndex ? { ...field, ...patch } : field
|
|
6023
|
+
);
|
|
6024
|
+
return { ...step, fields };
|
|
6025
|
+
})
|
|
6026
|
+
};
|
|
6027
|
+
});
|
|
6028
|
+
};
|
|
6029
|
+
const moveStep = (stepIndex, direction) => {
|
|
6030
|
+
setEditorState(
|
|
6031
|
+
(current) => current ? {
|
|
6032
|
+
...current,
|
|
6033
|
+
steps: moveItem(current.steps, stepIndex, stepIndex + direction)
|
|
6034
|
+
} : current
|
|
6035
|
+
);
|
|
6036
|
+
};
|
|
6037
|
+
const moveField = (stepIndex, fieldIndex, direction) => {
|
|
6038
|
+
setEditorState((current) => {
|
|
6039
|
+
if (!current) return current;
|
|
6040
|
+
return {
|
|
6041
|
+
...current,
|
|
6042
|
+
steps: current.steps.map(
|
|
6043
|
+
(step, index) => index === stepIndex ? { ...step, fields: moveItem(getFields(step), fieldIndex, fieldIndex + direction) } : step
|
|
6044
|
+
)
|
|
6045
|
+
};
|
|
6046
|
+
});
|
|
6047
|
+
};
|
|
6048
|
+
return /* @__PURE__ */ jsx30(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs27(
|
|
6049
|
+
AdminPage,
|
|
6050
|
+
{
|
|
6051
|
+
breadcrumbs: [
|
|
6052
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
6053
|
+
{ label: "Forms", href: formsPath },
|
|
6054
|
+
{ label: title }
|
|
6055
|
+
],
|
|
6056
|
+
description: "Manage form content and review recent responses without leaving Studio.",
|
|
6057
|
+
title: "Form",
|
|
6058
|
+
children: [
|
|
6059
|
+
loading ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
6060
|
+
error ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-error", children: error }) : null,
|
|
6061
|
+
savedMessage ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-success", children: savedMessage }) : null,
|
|
6062
|
+
!loading && !error && doc && editorState && formID ? /* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "1rem" }, children: [
|
|
6063
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-forms-summary-grid", children: [
|
|
6064
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-overview-stat", children: [
|
|
6065
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-overview-stat-label", children: "Workflow steps" }),
|
|
6066
|
+
/* @__PURE__ */ jsx30("strong", { children: stepCount }),
|
|
6067
|
+
/* @__PURE__ */ jsx30("p", { children: "Configured stages in the public form flow." })
|
|
6068
|
+
] }),
|
|
6069
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-overview-stat", children: [
|
|
6070
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-overview-stat-label", children: "Fields" }),
|
|
6071
|
+
/* @__PURE__ */ jsx30("strong", { children: fieldCount }),
|
|
6072
|
+
/* @__PURE__ */ jsx30("p", { children: "Total visible and conditional fields across every step." })
|
|
6073
|
+
] }),
|
|
6074
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-overview-stat", children: [
|
|
6075
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-overview-stat-label", children: "Recent submissions" }),
|
|
6076
|
+
/* @__PURE__ */ jsx30("strong", { children: submissions.length }),
|
|
6077
|
+
/* @__PURE__ */ jsx30("p", { children: latestSubmission ? `Latest response ${formatDate2(latestSubmission.submittedAt)}` : "No responses have been recorded yet." })
|
|
6078
|
+
] })
|
|
6079
|
+
] }),
|
|
6080
|
+
/* @__PURE__ */ jsxs27("section", { className: "orion-admin-form-board", style: toneStyle, children: [
|
|
6081
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-header", children: [
|
|
6082
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-heading", children: [
|
|
6083
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-kicker-row", children: [
|
|
6084
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-board-kicker", children: slug || "No slug set" }),
|
|
6085
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-board-meta", children: doc.updatedAt ? `Updated ${formatDate2(doc.updatedAt)}` : "Update time unavailable" })
|
|
6086
|
+
] }),
|
|
6087
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-title-row", children: [
|
|
6088
|
+
/* @__PURE__ */ jsx30("div", { className: "orion-admin-form-board-mark", children: getInitials2(title, slug) }),
|
|
6089
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-copy", children: [
|
|
6090
|
+
/* @__PURE__ */ jsx30("h2", { className: "orion-admin-form-board-title", children: title }),
|
|
6091
|
+
/* @__PURE__ */ jsx30("p", { className: "orion-admin-form-board-subtitle", children: editorState.successMessage.trim().length > 0 ? editorState.successMessage : "No success message set." })
|
|
6092
|
+
] })
|
|
6093
|
+
] })
|
|
6094
|
+
] }),
|
|
6095
|
+
/* @__PURE__ */ jsx30("div", { className: "orion-admin-form-board-actions", children: /* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-count", children: [
|
|
6096
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-board-count-value", children: submissions.length }),
|
|
6097
|
+
/* @__PURE__ */ jsxs27("span", { className: "orion-admin-form-board-count-label", children: [
|
|
6098
|
+
"response",
|
|
6099
|
+
submissions.length === 1 ? "" : "s"
|
|
6100
|
+
] })
|
|
6101
|
+
] }) })
|
|
6102
|
+
] }),
|
|
6103
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-form-board-metrics", children: [
|
|
6104
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-form-metric", children: [
|
|
6105
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-metric-label", children: "Submit button" }),
|
|
6106
|
+
/* @__PURE__ */ jsx30("strong", { className: "orion-admin-form-metric-value is-copy", children: editorState.submitLabel || "Submit" })
|
|
6107
|
+
] }),
|
|
6108
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-form-metric", children: [
|
|
6109
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-metric-label", children: "Admin notifications" }),
|
|
6110
|
+
/* @__PURE__ */ jsx30("strong", { className: "orion-admin-form-metric-value", children: editorState.sendAdmin ? "On" : "Off" })
|
|
6111
|
+
] }),
|
|
6112
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-form-metric", children: [
|
|
6113
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-metric-label", children: "Confirmation email" }),
|
|
6114
|
+
/* @__PURE__ */ jsx30("strong", { className: "orion-admin-form-metric-value", children: editorState.sendConfirmation ? "On" : "Off" })
|
|
6115
|
+
] }),
|
|
6116
|
+
/* @__PURE__ */ jsxs27("article", { className: "orion-admin-form-metric", children: [
|
|
6117
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-form-metric-label", children: "Latest response" }),
|
|
6118
|
+
/* @__PURE__ */ jsx30("strong", { className: "orion-admin-form-metric-value is-copy", children: latestSubmission ? formatDate2(latestSubmission.submittedAt) : "No activity yet" })
|
|
6119
|
+
] })
|
|
6120
|
+
] })
|
|
6121
|
+
] }),
|
|
6122
|
+
/* @__PURE__ */ jsxs27("div", { style: sectionGridStyle, children: [
|
|
6123
|
+
/* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "1rem" }, children: [
|
|
6124
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
|
|
6125
|
+
/* @__PURE__ */ jsx30("strong", { children: "Step preview" }),
|
|
6126
|
+
/* @__PURE__ */ jsx30("span", { children: "Review the public workflow as visitors will move through it." }),
|
|
6127
|
+
/* @__PURE__ */ jsx30("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: editorState.steps.length > 0 ? editorState.steps.map((record, stepIndex) => {
|
|
6128
|
+
const fields = getFields(record);
|
|
6129
|
+
return /* @__PURE__ */ jsxs27("div", { className: "orion-admin-form", children: [
|
|
6130
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
6131
|
+
/* @__PURE__ */ jsxs27("strong", { children: [
|
|
6132
|
+
"Step ",
|
|
6133
|
+
stepIndex + 1,
|
|
6134
|
+
": ",
|
|
6135
|
+
getNonEmptyText(record?.title, "Untitled Step")
|
|
6136
|
+
] }),
|
|
6137
|
+
getNonEmptyText(record?.subtitle) ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", style: { marginTop: "0.25rem" }, children: getNonEmptyText(record?.subtitle) }) : null
|
|
6138
|
+
] }),
|
|
6139
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-inline-actions", children: [
|
|
6140
|
+
/* @__PURE__ */ jsxs27("span", { className: "orion-admin-pill", children: [
|
|
6141
|
+
fields.length,
|
|
6142
|
+
" field",
|
|
6143
|
+
fields.length === 1 ? "" : "s"
|
|
6144
|
+
] }),
|
|
6145
|
+
record?.allowSkip === true ? /* @__PURE__ */ jsx30("span", { className: "orion-admin-pill", children: "Can skip" }) : null,
|
|
6146
|
+
getNonEmptyText(record?.nextLabel) ? /* @__PURE__ */ jsxs27("span", { className: "orion-admin-pill", children: [
|
|
6147
|
+
"Next: ",
|
|
6148
|
+
getNonEmptyText(record?.nextLabel)
|
|
6149
|
+
] }) : null
|
|
6150
|
+
] }),
|
|
6151
|
+
fields.length > 0 ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-list", children: fields.map((field, fieldIndex) => {
|
|
6152
|
+
const fieldRecord = field && typeof field === "object" && !Array.isArray(field) ? field : null;
|
|
6153
|
+
const type = getNonEmptyText(fieldRecord?.type, "text");
|
|
6154
|
+
const label = getNonEmptyText(
|
|
6155
|
+
fieldRecord?.label,
|
|
6156
|
+
getNonEmptyText(fieldRecord?.name, `Field ${fieldIndex + 1}`)
|
|
6157
|
+
);
|
|
6158
|
+
const helpText = getNonEmptyText(fieldRecord?.helpText);
|
|
6159
|
+
const condition = fieldRecord?.condition && typeof fieldRecord.condition === "object" && !Array.isArray(fieldRecord.condition) ? fieldRecord.condition : null;
|
|
6160
|
+
return /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-item", children: /* @__PURE__ */ jsxs27("div", { children: [
|
|
6161
|
+
/* @__PURE__ */ jsx30("strong", { children: label }),
|
|
6162
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-list-meta", children: [
|
|
6163
|
+
type,
|
|
6164
|
+
fieldRecord?.required === true ? " \xB7 required" : "",
|
|
6165
|
+
condition?.field && condition?.equals ? ` \xB7 when ${String(condition.field)} = ${String(condition.equals)}` : ""
|
|
6166
|
+
] }),
|
|
6167
|
+
helpText ? /* @__PURE__ */ jsx30(
|
|
6168
|
+
"div",
|
|
6169
|
+
{
|
|
6170
|
+
className: "orion-admin-list-meta",
|
|
6171
|
+
style: { marginTop: "0.25rem" },
|
|
6172
|
+
children: helpText
|
|
6173
|
+
}
|
|
6174
|
+
) : null
|
|
6175
|
+
] }) }, `field-${fieldIndex}`);
|
|
6176
|
+
}) }) : /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: "This step has no fields." })
|
|
6177
|
+
] }, `step-${stepIndex}`);
|
|
6178
|
+
}) : /* @__PURE__ */ jsxs27("div", { className: "orion-admin-empty-state", children: [
|
|
6179
|
+
/* @__PURE__ */ jsx30("strong", { children: "No steps configured" }),
|
|
6180
|
+
/* @__PURE__ */ jsx30("span", { children: "Add at least one step in Form settings to publish this form." })
|
|
6181
|
+
] }) })
|
|
6182
|
+
] }),
|
|
6183
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
|
|
6184
|
+
/* @__PURE__ */ jsx30("strong", { children: "Recent submissions" }),
|
|
6185
|
+
/* @__PURE__ */ jsx30("span", { children: "Jump from the form definition into the latest responses." }),
|
|
6186
|
+
/* @__PURE__ */ jsx30("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: submissions.length > 0 ? submissions.map((submission) => {
|
|
6187
|
+
const submissionID = typeof submission.id === "string" || typeof submission.id === "number" ? String(submission.id) : "";
|
|
6188
|
+
if (!submissionID) return null;
|
|
6189
|
+
const identity = getNameAndEmail2(submission.data);
|
|
6190
|
+
const previewFields = getPreviewFields2(submission.data, fieldLabels);
|
|
6191
|
+
const formSubmissionPath = resolveAdminPath(
|
|
6192
|
+
adminBasePath,
|
|
6193
|
+
`/forms/submissions/${submissionID}`
|
|
6194
|
+
);
|
|
6195
|
+
return /* @__PURE__ */ jsxs27(Link4, { className: "orion-admin-list-item", href: formSubmissionPath, children: [
|
|
6196
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
6197
|
+
/* @__PURE__ */ jsx30("strong", { children: identity.name || identity.email || "Submission" }),
|
|
6198
|
+
/* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: formatDate2(submission.submittedAt) }),
|
|
6199
|
+
previewFields.length > 0 ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", style: { marginTop: "0.3rem" }, children: previewFields.map((field) => `${field.label}: ${field.value}`).join(" \xB7 ") }) : null
|
|
6200
|
+
] }),
|
|
6201
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
|
|
6202
|
+
] }, submissionID);
|
|
6203
|
+
}) : /* @__PURE__ */ jsxs27("div", { className: "orion-admin-empty-state", children: [
|
|
6204
|
+
/* @__PURE__ */ jsx30("strong", { children: "No responses yet" }),
|
|
6205
|
+
/* @__PURE__ */ jsx30("span", { children: "This view will populate as soon as the form starts receiving traffic." })
|
|
6206
|
+
] }) })
|
|
6207
|
+
] })
|
|
6208
|
+
] }),
|
|
6209
|
+
/* @__PURE__ */ jsxs27("form", { className: "orion-admin-form", onSubmit: save, children: [
|
|
6210
|
+
/* @__PURE__ */ jsx30("strong", { children: "Form settings" }),
|
|
6211
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6212
|
+
"Title",
|
|
6213
|
+
/* @__PURE__ */ jsx30(
|
|
6214
|
+
"input",
|
|
6215
|
+
{
|
|
6216
|
+
onChange: (event) => setEditorState(
|
|
6217
|
+
(current) => current ? { ...current, title: event.target.value } : current
|
|
6218
|
+
),
|
|
6219
|
+
required: true,
|
|
6220
|
+
type: "text",
|
|
6221
|
+
value: editorState.title
|
|
6222
|
+
}
|
|
6223
|
+
)
|
|
6224
|
+
] }),
|
|
6225
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6226
|
+
"Slug",
|
|
6227
|
+
/* @__PURE__ */ jsx30(
|
|
6228
|
+
"input",
|
|
6229
|
+
{
|
|
6230
|
+
onChange: (event) => setEditorState(
|
|
6231
|
+
(current) => current ? { ...current, slug: event.target.value } : current
|
|
6232
|
+
),
|
|
6233
|
+
required: true,
|
|
6234
|
+
type: "text",
|
|
6235
|
+
value: editorState.slug
|
|
6236
|
+
}
|
|
6237
|
+
)
|
|
6238
|
+
] }),
|
|
6239
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6240
|
+
"Submit button",
|
|
6241
|
+
/* @__PURE__ */ jsx30(
|
|
6242
|
+
"input",
|
|
6243
|
+
{
|
|
6244
|
+
onChange: (event) => setEditorState(
|
|
6245
|
+
(current) => current ? { ...current, submitLabel: event.target.value } : current
|
|
6246
|
+
),
|
|
6247
|
+
type: "text",
|
|
6248
|
+
value: editorState.submitLabel
|
|
6249
|
+
}
|
|
6250
|
+
)
|
|
6251
|
+
] }),
|
|
6252
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6253
|
+
"Success message",
|
|
6254
|
+
/* @__PURE__ */ jsx30(
|
|
6255
|
+
"textarea",
|
|
6256
|
+
{
|
|
6257
|
+
onChange: (event) => setEditorState(
|
|
6258
|
+
(current) => current ? { ...current, successMessage: event.target.value } : current
|
|
6259
|
+
),
|
|
6260
|
+
rows: 4,
|
|
6261
|
+
value: editorState.successMessage
|
|
6262
|
+
}
|
|
6263
|
+
)
|
|
6264
|
+
] }),
|
|
6265
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
|
|
6266
|
+
/* @__PURE__ */ jsx30("strong", { children: "Email behavior" }),
|
|
6267
|
+
/* @__PURE__ */ jsxs27("div", { style: { display: "grid", gap: "0.85rem", marginTop: "0.9rem" }, children: [
|
|
6268
|
+
/* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
|
|
6269
|
+
/* @__PURE__ */ jsx30(
|
|
6270
|
+
"input",
|
|
6271
|
+
{
|
|
6272
|
+
checked: editorState.sendAdmin,
|
|
6273
|
+
onChange: (event) => setEditorState(
|
|
6274
|
+
(current) => current ? { ...current, sendAdmin: event.target.checked } : current
|
|
6275
|
+
),
|
|
6276
|
+
type: "checkbox"
|
|
6277
|
+
}
|
|
6278
|
+
),
|
|
6279
|
+
"Send admin notifications"
|
|
6280
|
+
] }),
|
|
6281
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6282
|
+
"Admin recipients",
|
|
6283
|
+
/* @__PURE__ */ jsx30(
|
|
6284
|
+
"textarea",
|
|
6285
|
+
{
|
|
6286
|
+
onChange: (event) => setEditorState(
|
|
6287
|
+
(current) => current ? { ...current, adminRecipientsText: event.target.value } : current
|
|
6288
|
+
),
|
|
6289
|
+
placeholder: "one@email.com\ntwo@email.com",
|
|
6290
|
+
rows: 4,
|
|
6291
|
+
value: editorState.adminRecipientsText
|
|
6292
|
+
}
|
|
6293
|
+
)
|
|
6294
|
+
] }),
|
|
6295
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6296
|
+
"Admin subject",
|
|
6297
|
+
/* @__PURE__ */ jsx30(
|
|
6298
|
+
"input",
|
|
6299
|
+
{
|
|
6300
|
+
onChange: (event) => setEditorState(
|
|
6301
|
+
(current) => current ? { ...current, adminSubject: event.target.value } : current
|
|
6302
|
+
),
|
|
6303
|
+
type: "text",
|
|
6304
|
+
value: editorState.adminSubject
|
|
6305
|
+
}
|
|
6306
|
+
)
|
|
6307
|
+
] }),
|
|
6308
|
+
/* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
|
|
6309
|
+
/* @__PURE__ */ jsx30(
|
|
6310
|
+
"input",
|
|
6311
|
+
{
|
|
6312
|
+
checked: editorState.sendConfirmation,
|
|
6313
|
+
onChange: (event) => setEditorState(
|
|
6314
|
+
(current) => current ? { ...current, sendConfirmation: event.target.checked } : current
|
|
6315
|
+
),
|
|
6316
|
+
type: "checkbox"
|
|
6317
|
+
}
|
|
6318
|
+
),
|
|
6319
|
+
"Send confirmation email"
|
|
6320
|
+
] }),
|
|
6321
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6322
|
+
"Confirmation subject",
|
|
6323
|
+
/* @__PURE__ */ jsx30(
|
|
6324
|
+
"input",
|
|
6325
|
+
{
|
|
6326
|
+
onChange: (event) => setEditorState(
|
|
6327
|
+
(current) => current ? { ...current, confirmationSubject: event.target.value } : current
|
|
6328
|
+
),
|
|
6329
|
+
type: "text",
|
|
6330
|
+
value: editorState.confirmationSubject
|
|
6331
|
+
}
|
|
6332
|
+
)
|
|
6333
|
+
] }),
|
|
6334
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6335
|
+
"Confirmation heading",
|
|
6336
|
+
/* @__PURE__ */ jsx30(
|
|
6337
|
+
"input",
|
|
6338
|
+
{
|
|
6339
|
+
onChange: (event) => setEditorState(
|
|
6340
|
+
(current) => current ? { ...current, confirmationHeading: event.target.value } : current
|
|
6341
|
+
),
|
|
6342
|
+
type: "text",
|
|
6343
|
+
value: editorState.confirmationHeading
|
|
6344
|
+
}
|
|
6345
|
+
)
|
|
6346
|
+
] }),
|
|
6347
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6348
|
+
"Confirmation message",
|
|
6349
|
+
/* @__PURE__ */ jsx30(
|
|
6350
|
+
"textarea",
|
|
6351
|
+
{
|
|
6352
|
+
onChange: (event) => setEditorState(
|
|
6353
|
+
(current) => current ? { ...current, confirmationMessage: event.target.value } : current
|
|
6354
|
+
),
|
|
6355
|
+
rows: 4,
|
|
6356
|
+
value: editorState.confirmationMessage
|
|
6357
|
+
}
|
|
6358
|
+
)
|
|
6359
|
+
] })
|
|
6360
|
+
] })
|
|
6361
|
+
] }),
|
|
6362
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-card orion-admin-workflow-editor", children: [
|
|
6363
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-workflow-editor-header", children: [
|
|
6364
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
6365
|
+
/* @__PURE__ */ jsx30("strong", { children: "Form steps" }),
|
|
6366
|
+
/* @__PURE__ */ jsx30("span", { children: "Build the visitor flow, then edit each step's fields below." })
|
|
6367
|
+
] }),
|
|
6368
|
+
/* @__PURE__ */ jsx30(
|
|
6369
|
+
"button",
|
|
6370
|
+
{
|
|
6371
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6372
|
+
onClick: () => setEditorState(
|
|
6373
|
+
(current) => current ? { ...current, steps: [...current.steps, blankStep()] } : current
|
|
6374
|
+
),
|
|
6375
|
+
type: "button",
|
|
6376
|
+
children: "Add step"
|
|
6377
|
+
}
|
|
6378
|
+
)
|
|
6379
|
+
] }),
|
|
6380
|
+
editorState.steps.length === 0 ? /* @__PURE__ */ jsxs27("div", { className: "orion-admin-empty-state", children: [
|
|
6381
|
+
/* @__PURE__ */ jsx30("strong", { children: "No steps configured" }),
|
|
6382
|
+
/* @__PURE__ */ jsx30("span", { children: "Add a first step to start building the public form flow." })
|
|
6383
|
+
] }) : null,
|
|
6384
|
+
/* @__PURE__ */ jsx30("div", { className: "orion-admin-step-editor-list", children: editorState.steps.map((step, stepIndex) => {
|
|
6385
|
+
const fields = getFields(step);
|
|
6386
|
+
const requiredCount = fields.filter((field) => field.required === true).length;
|
|
6387
|
+
return /* @__PURE__ */ jsxs27("details", { className: "orion-admin-step-editor", open: true, children: [
|
|
6388
|
+
/* @__PURE__ */ jsxs27("summary", { className: "orion-admin-step-editor-summary", children: [
|
|
6389
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-workflow-node-number", children: stepIndex + 1 }),
|
|
6390
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-step-editor-title", children: getStepTitle(step, stepIndex) }),
|
|
6391
|
+
/* @__PURE__ */ jsxs27("span", { className: "orion-admin-step-editor-meta", children: [
|
|
6392
|
+
fields.length,
|
|
6393
|
+
" field",
|
|
6394
|
+
fields.length === 1 ? "" : "s",
|
|
6395
|
+
requiredCount > 0 ? ` \xB7 ${requiredCount} required` : ""
|
|
6396
|
+
] }),
|
|
6397
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-workflow-node-destination", children: getStepDestination(stepIndex, editorState.steps.length) })
|
|
6398
|
+
] }),
|
|
6399
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-step-editor-body", children: [
|
|
6400
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-step-editor-actions", children: [
|
|
6401
|
+
/* @__PURE__ */ jsx30(
|
|
6402
|
+
"button",
|
|
6403
|
+
{
|
|
6404
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6405
|
+
disabled: stepIndex === 0,
|
|
6406
|
+
onClick: () => moveStep(stepIndex, -1),
|
|
6407
|
+
type: "button",
|
|
6408
|
+
children: "Move up"
|
|
6409
|
+
}
|
|
6410
|
+
),
|
|
6411
|
+
/* @__PURE__ */ jsx30(
|
|
6412
|
+
"button",
|
|
6413
|
+
{
|
|
6414
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6415
|
+
disabled: stepIndex === editorState.steps.length - 1,
|
|
6416
|
+
onClick: () => moveStep(stepIndex, 1),
|
|
6417
|
+
type: "button",
|
|
6418
|
+
children: "Move down"
|
|
6419
|
+
}
|
|
6420
|
+
),
|
|
6421
|
+
/* @__PURE__ */ jsx30(
|
|
6422
|
+
"button",
|
|
6423
|
+
{
|
|
6424
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6425
|
+
onClick: () => setEditorState(
|
|
6426
|
+
(current) => current ? {
|
|
6427
|
+
...current,
|
|
6428
|
+
steps: current.steps.filter((_, index) => index !== stepIndex)
|
|
6429
|
+
} : current
|
|
6430
|
+
),
|
|
6431
|
+
type: "button",
|
|
6432
|
+
children: "Remove step"
|
|
6433
|
+
}
|
|
6434
|
+
)
|
|
6435
|
+
] }),
|
|
6436
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-step-settings-grid", children: [
|
|
6437
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6438
|
+
"Step title",
|
|
6439
|
+
/* @__PURE__ */ jsx30(
|
|
6440
|
+
"input",
|
|
6441
|
+
{
|
|
6442
|
+
onChange: (event) => updateStep(stepIndex, { title: event.target.value }),
|
|
6443
|
+
type: "text",
|
|
6444
|
+
value: getNonEmptyText(step.title)
|
|
6445
|
+
}
|
|
6446
|
+
)
|
|
6447
|
+
] }),
|
|
6448
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6449
|
+
"Next button label",
|
|
6450
|
+
/* @__PURE__ */ jsx30(
|
|
6451
|
+
"input",
|
|
6452
|
+
{
|
|
6453
|
+
onChange: (event) => updateStep(stepIndex, { nextLabel: event.target.value }),
|
|
6454
|
+
placeholder: "Next",
|
|
6455
|
+
type: "text",
|
|
6456
|
+
value: getNonEmptyText(step.nextLabel)
|
|
6457
|
+
}
|
|
6458
|
+
)
|
|
6459
|
+
] })
|
|
6460
|
+
] }),
|
|
6461
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6462
|
+
"Step intro text",
|
|
6463
|
+
/* @__PURE__ */ jsx30(
|
|
6464
|
+
"textarea",
|
|
6465
|
+
{
|
|
6466
|
+
onChange: (event) => updateStep(stepIndex, { subtitle: event.target.value }),
|
|
6467
|
+
rows: 3,
|
|
6468
|
+
value: getNonEmptyText(step.subtitle)
|
|
6469
|
+
}
|
|
6470
|
+
)
|
|
6471
|
+
] }),
|
|
6472
|
+
/* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
|
|
6473
|
+
/* @__PURE__ */ jsx30(
|
|
6474
|
+
"input",
|
|
6475
|
+
{
|
|
6476
|
+
checked: step.allowSkip === true,
|
|
6477
|
+
onChange: (event) => updateStep(stepIndex, { allowSkip: event.target.checked }),
|
|
6478
|
+
type: "checkbox"
|
|
6479
|
+
}
|
|
6480
|
+
),
|
|
6481
|
+
"Allow visitors to skip this step"
|
|
6482
|
+
] }),
|
|
6483
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-field-list-header", children: [
|
|
6484
|
+
/* @__PURE__ */ jsxs27("div", { children: [
|
|
6485
|
+
/* @__PURE__ */ jsx30("strong", { children: "Fields in this step" }),
|
|
6486
|
+
/* @__PURE__ */ jsx30("span", { children: "These appear together before the visitor moves to the next step." })
|
|
6487
|
+
] }),
|
|
6488
|
+
/* @__PURE__ */ jsx30(
|
|
6489
|
+
"button",
|
|
6490
|
+
{
|
|
6491
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6492
|
+
onClick: () => setEditorState(
|
|
6493
|
+
(current) => current ? {
|
|
6494
|
+
...current,
|
|
6495
|
+
steps: current.steps.map(
|
|
6496
|
+
(currentStep, index) => index === stepIndex ? { ...currentStep, fields: [...getFields(currentStep), blankField()] } : currentStep
|
|
6497
|
+
)
|
|
6498
|
+
} : current
|
|
6499
|
+
),
|
|
6500
|
+
type: "button",
|
|
6501
|
+
children: "Add field"
|
|
6502
|
+
}
|
|
6503
|
+
)
|
|
6504
|
+
] }),
|
|
6505
|
+
fields.length > 0 ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-field-editor-list", children: fields.map((field, fieldIndex) => {
|
|
6506
|
+
const label = getFieldLabel(field, fieldIndex);
|
|
6507
|
+
const fieldType = getNonEmptyText(field.type, "text");
|
|
6508
|
+
return /* @__PURE__ */ jsxs27("details", { className: "orion-admin-field-editor", children: [
|
|
6509
|
+
/* @__PURE__ */ jsxs27("summary", { className: "orion-admin-field-editor-summary", children: [
|
|
6510
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-field-order", children: fieldIndex + 1 }),
|
|
6511
|
+
/* @__PURE__ */ jsx30("span", { className: "orion-admin-field-editor-title", children: label }),
|
|
6512
|
+
/* @__PURE__ */ jsxs27("span", { className: "orion-admin-field-editor-meta", children: [
|
|
6513
|
+
formatFieldTypeLabel(fieldType),
|
|
6514
|
+
field.required === true ? " \xB7 Required" : ""
|
|
6515
|
+
] })
|
|
6516
|
+
] }),
|
|
6517
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-field-editor-body", children: [
|
|
6518
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-step-editor-actions", children: [
|
|
6519
|
+
/* @__PURE__ */ jsx30(
|
|
6520
|
+
"button",
|
|
6521
|
+
{
|
|
6522
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6523
|
+
disabled: fieldIndex === 0,
|
|
6524
|
+
onClick: () => moveField(stepIndex, fieldIndex, -1),
|
|
6525
|
+
type: "button",
|
|
6526
|
+
children: "Move up"
|
|
6527
|
+
}
|
|
6528
|
+
),
|
|
6529
|
+
/* @__PURE__ */ jsx30(
|
|
6530
|
+
"button",
|
|
6531
|
+
{
|
|
6532
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6533
|
+
disabled: fieldIndex === fields.length - 1,
|
|
6534
|
+
onClick: () => moveField(stepIndex, fieldIndex, 1),
|
|
6535
|
+
type: "button",
|
|
6536
|
+
children: "Move down"
|
|
6537
|
+
}
|
|
6538
|
+
),
|
|
6539
|
+
/* @__PURE__ */ jsx30(
|
|
6540
|
+
"button",
|
|
6541
|
+
{
|
|
6542
|
+
className: "orion-admin-action-button orion-admin-action-button--ghost",
|
|
6543
|
+
onClick: () => setEditorState((current) => {
|
|
6544
|
+
if (!current) return current;
|
|
6545
|
+
return {
|
|
6546
|
+
...current,
|
|
6547
|
+
steps: current.steps.map(
|
|
6548
|
+
(currentStep, index) => index === stepIndex ? {
|
|
6549
|
+
...currentStep,
|
|
6550
|
+
fields: getFields(currentStep).filter(
|
|
6551
|
+
(_, currentFieldIndex) => currentFieldIndex !== fieldIndex
|
|
6552
|
+
)
|
|
6553
|
+
} : currentStep
|
|
6554
|
+
)
|
|
6555
|
+
};
|
|
6556
|
+
}),
|
|
6557
|
+
type: "button",
|
|
6558
|
+
children: "Remove field"
|
|
6559
|
+
}
|
|
6560
|
+
)
|
|
6561
|
+
] }),
|
|
6562
|
+
/* @__PURE__ */ jsxs27("div", { className: "orion-admin-step-settings-grid", children: [
|
|
6563
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6564
|
+
"Field label",
|
|
6565
|
+
/* @__PURE__ */ jsx30(
|
|
6566
|
+
"input",
|
|
6567
|
+
{
|
|
6568
|
+
onChange: (event) => {
|
|
6569
|
+
const nextLabel = event.target.value;
|
|
6570
|
+
const currentName = getNonEmptyText(field.name);
|
|
6571
|
+
updateField(stepIndex, fieldIndex, {
|
|
6572
|
+
label: nextLabel,
|
|
6573
|
+
name: currentName || slugifyFieldName(nextLabel)
|
|
6574
|
+
});
|
|
6575
|
+
},
|
|
6576
|
+
type: "text",
|
|
6577
|
+
value: label
|
|
6578
|
+
}
|
|
6579
|
+
)
|
|
6580
|
+
] }),
|
|
6581
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6582
|
+
"Field type",
|
|
6583
|
+
/* @__PURE__ */ jsx30(
|
|
6584
|
+
"select",
|
|
6585
|
+
{
|
|
6586
|
+
onChange: (event) => updateField(stepIndex, fieldIndex, { type: event.target.value }),
|
|
6587
|
+
value: fieldType,
|
|
6588
|
+
children: fieldTypeOptions.map((option) => /* @__PURE__ */ jsx30("option", { value: option, children: formatFieldTypeLabel(option) }, option))
|
|
6589
|
+
}
|
|
6590
|
+
)
|
|
6591
|
+
] })
|
|
6592
|
+
] }),
|
|
6593
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6594
|
+
"Field key",
|
|
6595
|
+
/* @__PURE__ */ jsx30(
|
|
6596
|
+
"input",
|
|
6597
|
+
{
|
|
6598
|
+
onChange: (event) => updateField(stepIndex, fieldIndex, { name: event.target.value }),
|
|
6599
|
+
type: "text",
|
|
6600
|
+
value: getNonEmptyText(field.name)
|
|
6601
|
+
}
|
|
6602
|
+
)
|
|
6603
|
+
] }),
|
|
6604
|
+
/* @__PURE__ */ jsxs27("label", { style: checkboxLabelStyle, children: [
|
|
6605
|
+
/* @__PURE__ */ jsx30(
|
|
6606
|
+
"input",
|
|
6607
|
+
{
|
|
6608
|
+
checked: field.required === true,
|
|
6609
|
+
onChange: (event) => updateField(stepIndex, fieldIndex, { required: event.target.checked }),
|
|
6610
|
+
type: "checkbox"
|
|
6611
|
+
}
|
|
6612
|
+
),
|
|
6613
|
+
"Required"
|
|
6614
|
+
] }),
|
|
6615
|
+
/* @__PURE__ */ jsxs27("label", { children: [
|
|
6616
|
+
"Help text",
|
|
6617
|
+
/* @__PURE__ */ jsx30(
|
|
6618
|
+
"textarea",
|
|
6619
|
+
{
|
|
6620
|
+
onChange: (event) => updateField(stepIndex, fieldIndex, { helpText: event.target.value }),
|
|
6621
|
+
rows: 2,
|
|
6622
|
+
value: getNonEmptyText(field.helpText)
|
|
6623
|
+
}
|
|
6624
|
+
)
|
|
6625
|
+
] }),
|
|
6626
|
+
["select", "radio", "checkbox-group"].includes(fieldType) ? /* @__PURE__ */ jsxs27("label", { children: [
|
|
6627
|
+
"Options",
|
|
6628
|
+
/* @__PURE__ */ jsx30(
|
|
6629
|
+
"textarea",
|
|
6630
|
+
{
|
|
6631
|
+
onChange: (event) => updateField(stepIndex, fieldIndex, {
|
|
6632
|
+
options: fromOptionsText(event.target.value)
|
|
6633
|
+
}),
|
|
6634
|
+
placeholder: "Option one\nOption two",
|
|
6635
|
+
rows: 4,
|
|
6636
|
+
value: toOptionsText(field.options)
|
|
6637
|
+
}
|
|
6638
|
+
)
|
|
6639
|
+
] }) : null
|
|
6640
|
+
] })
|
|
6641
|
+
] }, `edit-field-${stepIndex}-${fieldIndex}`);
|
|
6642
|
+
}) }) : /* @__PURE__ */ jsxs27("div", { className: "orion-admin-empty-state", children: [
|
|
6643
|
+
/* @__PURE__ */ jsx30("strong", { children: "No fields in this step" }),
|
|
6644
|
+
/* @__PURE__ */ jsx30("span", { children: "Add a field so visitors have something to answer here." })
|
|
6645
|
+
] })
|
|
6646
|
+
] })
|
|
6647
|
+
] }, `edit-step-${stepIndex}`);
|
|
6648
|
+
}) })
|
|
6649
|
+
] }),
|
|
6650
|
+
/* @__PURE__ */ jsx30("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Form" })
|
|
6651
|
+
] })
|
|
6652
|
+
] })
|
|
6653
|
+
] }) : null
|
|
6654
|
+
]
|
|
6655
|
+
}
|
|
6656
|
+
) });
|
|
6657
|
+
}
|
|
6658
|
+
|
|
6659
|
+
// src/admin/components/studio/AdminStudioFormSubmissionView.tsx
|
|
6660
|
+
import Link5 from "next/link";
|
|
6661
|
+
import { useEffect as useEffect19, useMemo as useMemo15, useState as useState21 } from "react";
|
|
6662
|
+
import { Fragment as Fragment6, jsx as jsx31, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
6663
|
+
var sectionGridStyle2 = {
|
|
6664
|
+
display: "grid",
|
|
6665
|
+
gap: "1rem",
|
|
6666
|
+
gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))"
|
|
6667
|
+
};
|
|
6668
|
+
var nestedListStyle = {
|
|
6669
|
+
display: "grid",
|
|
6670
|
+
gap: "0.45rem",
|
|
6671
|
+
margin: 0,
|
|
6672
|
+
padding: 0
|
|
6673
|
+
};
|
|
6674
|
+
var renderFieldValue = (value) => {
|
|
6675
|
+
if (value === null || value === void 0) {
|
|
6676
|
+
return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
|
|
6677
|
+
}
|
|
6678
|
+
if (typeof value === "boolean") {
|
|
6679
|
+
return value ? "Yes" : "No";
|
|
6680
|
+
}
|
|
6681
|
+
if (typeof value === "number") {
|
|
6682
|
+
return String(value);
|
|
6683
|
+
}
|
|
6684
|
+
if (typeof value === "string") {
|
|
6685
|
+
return value.trim().length > 0 ? value : /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
|
|
6686
|
+
}
|
|
6687
|
+
if (Array.isArray(value)) {
|
|
6688
|
+
const entries = value.filter((entry) => entry !== null && entry !== void 0 && entry !== "");
|
|
6689
|
+
if (entries.length === 0) {
|
|
6690
|
+
return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
|
|
6691
|
+
}
|
|
6692
|
+
return /* @__PURE__ */ jsx31("ul", { style: nestedListStyle, children: entries.map((entry, index) => /* @__PURE__ */ jsx31("li", { children: renderFieldValue(entry) }, index)) });
|
|
6693
|
+
}
|
|
6694
|
+
if (typeof value === "object") {
|
|
6695
|
+
const entries = Object.entries(value).filter(
|
|
6696
|
+
([, entryValue]) => entryValue !== null && entryValue !== void 0 && entryValue !== ""
|
|
6697
|
+
);
|
|
6698
|
+
if (entries.length === 0) {
|
|
6699
|
+
return /* @__PURE__ */ jsx31("span", { className: "orion-admin-list-meta", children: "No value" });
|
|
6700
|
+
}
|
|
6701
|
+
return /* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.65rem" }, children: entries.map(([key, entryValue]) => /* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6702
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: humanizeKey2(key) }),
|
|
6703
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: renderFieldValue(entryValue) })
|
|
6704
|
+
] }, key)) });
|
|
6705
|
+
}
|
|
6706
|
+
return String(value);
|
|
6707
|
+
};
|
|
6708
|
+
function getSubmissionIDFromPathname(pathname) {
|
|
6709
|
+
return getIDFromPathname(pathname, "/forms/submissions/");
|
|
6710
|
+
}
|
|
6711
|
+
function AdminStudioFormSubmissionView(props) {
|
|
6712
|
+
const formsCollectionSlug = getPropString14(props, "formsCollectionSlug", "forms");
|
|
6713
|
+
const formSubmissionsCollectionSlug = getPropString14(
|
|
6714
|
+
props,
|
|
6715
|
+
"formSubmissionsCollectionSlug",
|
|
6716
|
+
"form-submissions"
|
|
6717
|
+
);
|
|
6718
|
+
const adminBasePath = useAdminBasePath();
|
|
6719
|
+
const formsPath = resolveAdminPath(adminBasePath, "/forms");
|
|
6720
|
+
const submissionIDFromParams = useMemo15(() => getParam3(props.params, "id"), [props.params]);
|
|
6721
|
+
const [submissionID, setSubmissionID] = useState21(submissionIDFromParams);
|
|
6722
|
+
const [didResolvePathFallback, setDidResolvePathFallback] = useState21(false);
|
|
6723
|
+
const [doc, setDoc] = useState21(null);
|
|
6724
|
+
const [formDoc, setFormDoc] = useState21(null);
|
|
6725
|
+
const [loading, setLoading] = useState21(true);
|
|
6726
|
+
const [error, setError] = useState21(null);
|
|
6727
|
+
const [confirmDelete, setConfirmDelete] = useState21(false);
|
|
6728
|
+
const [deleting, setDeleting] = useState21(false);
|
|
6729
|
+
useEffect19(() => {
|
|
6730
|
+
if (submissionIDFromParams) {
|
|
6731
|
+
setSubmissionID(submissionIDFromParams);
|
|
6732
|
+
setDidResolvePathFallback(true);
|
|
6733
|
+
return;
|
|
6734
|
+
}
|
|
6735
|
+
if (typeof window !== "undefined") {
|
|
6736
|
+
setSubmissionID(getSubmissionIDFromPathname(window.location.pathname));
|
|
6737
|
+
}
|
|
6738
|
+
setDidResolvePathFallback(true);
|
|
6739
|
+
}, [submissionIDFromParams]);
|
|
6740
|
+
const loadDoc = async (id) => {
|
|
6741
|
+
setLoading(true);
|
|
6742
|
+
setError(null);
|
|
6743
|
+
try {
|
|
6744
|
+
const response = await fetch(
|
|
6745
|
+
`/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(id)}?depth=2&draft=true`,
|
|
6746
|
+
{
|
|
6747
|
+
credentials: "include"
|
|
6748
|
+
}
|
|
6749
|
+
);
|
|
6750
|
+
if (!response.ok) {
|
|
6751
|
+
throw new Error(`Failed to load submission (${response.status}).`);
|
|
6752
|
+
}
|
|
6753
|
+
const nextDoc = await response.json();
|
|
6754
|
+
const relatedForm = nextDoc.form && typeof nextDoc.form === "object" && !Array.isArray(nextDoc.form) ? nextDoc.form : null;
|
|
6755
|
+
let nextFormDoc = relatedForm;
|
|
6756
|
+
const relatedFormID2 = getFormID3(nextDoc.form);
|
|
6757
|
+
if (!nextFormDoc && relatedFormID2) {
|
|
6758
|
+
const formResponse = await fetch(
|
|
6759
|
+
`/api/${formsCollectionSlug}/${encodeURIComponent(relatedFormID2)}?depth=0&draft=true`,
|
|
6760
|
+
{
|
|
6761
|
+
credentials: "include"
|
|
6762
|
+
}
|
|
6763
|
+
);
|
|
6764
|
+
if (formResponse.ok) {
|
|
6765
|
+
nextFormDoc = await formResponse.json();
|
|
6766
|
+
}
|
|
6767
|
+
}
|
|
6768
|
+
setDoc(nextDoc);
|
|
6769
|
+
setFormDoc(nextFormDoc);
|
|
6770
|
+
} catch (loadError) {
|
|
6771
|
+
setError(loadError instanceof Error ? loadError.message : "Failed to load submission.");
|
|
6772
|
+
setDoc(null);
|
|
6773
|
+
setFormDoc(null);
|
|
6774
|
+
} finally {
|
|
6775
|
+
setLoading(false);
|
|
6776
|
+
}
|
|
6777
|
+
};
|
|
6778
|
+
useEffect19(() => {
|
|
6779
|
+
if (!submissionID) {
|
|
6780
|
+
return;
|
|
6781
|
+
}
|
|
6782
|
+
void loadDoc(submissionID);
|
|
6783
|
+
}, [formsCollectionSlug, formSubmissionsCollectionSlug, submissionID]);
|
|
6784
|
+
const deleteSubmission = async () => {
|
|
6785
|
+
if (!submissionID) {
|
|
6786
|
+
return;
|
|
6787
|
+
}
|
|
6788
|
+
setDeleting(true);
|
|
6789
|
+
setError(null);
|
|
6790
|
+
try {
|
|
6791
|
+
const response = await fetch(`/api/${formSubmissionsCollectionSlug}/${encodeURIComponent(submissionID)}`, {
|
|
6792
|
+
credentials: "include",
|
|
6793
|
+
method: "DELETE"
|
|
6794
|
+
});
|
|
6795
|
+
if (!response.ok) {
|
|
6796
|
+
throw new Error(`Failed to delete submission (${response.status}).`);
|
|
6797
|
+
}
|
|
6798
|
+
const relatedFormID2 = doc ? getFormID3(doc.form) : "";
|
|
6799
|
+
const targetHref = relatedFormID2 ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID2}`) : formsPath;
|
|
6800
|
+
window.location.assign(targetHref);
|
|
6801
|
+
} catch (deleteError) {
|
|
6802
|
+
setError(deleteError instanceof Error ? deleteError.message : "Failed to delete submission.");
|
|
6803
|
+
setDeleting(false);
|
|
6804
|
+
}
|
|
6805
|
+
};
|
|
6806
|
+
if (!submissionID && !didResolvePathFallback) {
|
|
6807
|
+
return /* @__PURE__ */ jsx31(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx31(
|
|
6808
|
+
AdminPage,
|
|
6809
|
+
{
|
|
6810
|
+
breadcrumbs: [
|
|
6811
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
6812
|
+
{ label: "Forms", href: formsPath },
|
|
6813
|
+
{ label: "Submission" }
|
|
6814
|
+
],
|
|
6815
|
+
description: "Loading submission workspace...",
|
|
6816
|
+
title: "Submission",
|
|
6817
|
+
children: /* @__PURE__ */ jsx31(Fragment6, {})
|
|
6818
|
+
}
|
|
6819
|
+
) });
|
|
6820
|
+
}
|
|
6821
|
+
const relatedFormID = doc ? getFormID3(doc.form) : "";
|
|
6822
|
+
const formPath = relatedFormID ? resolveAdminPath(adminBasePath, `/forms/${relatedFormID}`) : formsPath;
|
|
6823
|
+
const formTitle = formDoc ? getFormTitle2(formDoc) : getFormTitle2(doc?.formSlug);
|
|
6824
|
+
const uploads = doc ? getUploads2(doc.files) : [];
|
|
6825
|
+
const identity = doc ? getNameAndEmail2(doc.data) : {};
|
|
6826
|
+
const fieldLabels = formDoc ? buildFieldLabelMap2(formDoc) : /* @__PURE__ */ new Map();
|
|
6827
|
+
const previewFields = doc ? getPreviewFields2(doc.data, fieldLabels) : [];
|
|
6828
|
+
const answerEntries = doc && doc.data && typeof doc.data === "object" ? Object.entries(doc.data) : [];
|
|
6829
|
+
return /* @__PURE__ */ jsx31(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs28(
|
|
6830
|
+
AdminPage,
|
|
6831
|
+
{
|
|
6832
|
+
breadcrumbs: [
|
|
6833
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
6834
|
+
{ label: "Forms", href: formsPath },
|
|
6835
|
+
...relatedFormID ? [{ label: formTitle, href: formPath }] : [{ label: formTitle }],
|
|
6836
|
+
{ label: "Submission" }
|
|
6837
|
+
],
|
|
6838
|
+
description: "Review the submitted answers, related files, and linked form details.",
|
|
6839
|
+
title: "Submission",
|
|
6840
|
+
children: [
|
|
6841
|
+
loading ? /* @__PURE__ */ jsx31("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
6842
|
+
error ? /* @__PURE__ */ jsx31("div", { className: "orion-admin-error", children: error }) : null,
|
|
6843
|
+
!loading && !error && doc && submissionID ? /* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: "1rem" }, children: [
|
|
6844
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-forms-summary-grid", children: [
|
|
6845
|
+
/* @__PURE__ */ jsxs28("article", { className: "orion-admin-overview-stat", children: [
|
|
6846
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-overview-stat-label", children: "Submitted" }),
|
|
6847
|
+
/* @__PURE__ */ jsx31("strong", { children: formatDate2(doc.submittedAt) }),
|
|
6848
|
+
/* @__PURE__ */ jsx31("p", { children: "Captured timestamp for this response." })
|
|
6849
|
+
] }),
|
|
6850
|
+
/* @__PURE__ */ jsxs28("article", { className: "orion-admin-overview-stat", children: [
|
|
6851
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-overview-stat-label", children: "Uploads" }),
|
|
6852
|
+
/* @__PURE__ */ jsx31("strong", { children: uploads.length }),
|
|
6853
|
+
/* @__PURE__ */ jsx31("p", { children: "Files attached by the submitter." })
|
|
6854
|
+
] }),
|
|
6855
|
+
/* @__PURE__ */ jsxs28("article", { className: "orion-admin-overview-stat", children: [
|
|
6856
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-overview-stat-label", children: "Highlighted answers" }),
|
|
6857
|
+
/* @__PURE__ */ jsx31("strong", { children: previewFields.length }),
|
|
6858
|
+
/* @__PURE__ */ jsx31("p", { children: "Readable answer previews from this response." })
|
|
6859
|
+
] })
|
|
6860
|
+
] }),
|
|
6861
|
+
/* @__PURE__ */ jsxs28("div", { style: sectionGridStyle2, children: [
|
|
6862
|
+
/* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "1rem" }, children: /* @__PURE__ */ jsxs28("div", { className: "orion-admin-card", children: [
|
|
6863
|
+
/* @__PURE__ */ jsx31("strong", { children: "Response details" }),
|
|
6864
|
+
/* @__PURE__ */ jsx31("span", { children: "Formatted answers using the current form field labels when available." }),
|
|
6865
|
+
/* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.85rem", marginTop: "1rem" }, children: answerEntries.length > 0 ? answerEntries.map(([key, value]) => /* @__PURE__ */ jsxs28("div", { className: "orion-admin-form", children: [
|
|
6866
|
+
/* @__PURE__ */ jsxs28("div", { children: [
|
|
6867
|
+
/* @__PURE__ */ jsx31("strong", { children: fieldLabels.get(key) || humanizeKey2(key) }),
|
|
6868
|
+
/* @__PURE__ */ jsx31("div", { className: "orion-admin-list-meta", children: key })
|
|
6869
|
+
] }),
|
|
6870
|
+
/* @__PURE__ */ jsx31("div", { children: renderFieldValue(value) })
|
|
6871
|
+
] }, key)) : /* @__PURE__ */ jsxs28("div", { className: "orion-admin-empty-state", children: [
|
|
6872
|
+
/* @__PURE__ */ jsx31("strong", { children: "No answers available" }),
|
|
6873
|
+
/* @__PURE__ */ jsx31("span", { children: "This submission does not contain visible response details." })
|
|
6874
|
+
] }) })
|
|
6875
|
+
] }) }),
|
|
6876
|
+
/* @__PURE__ */ jsxs28("div", { style: { display: "grid", gap: "1rem" }, children: [
|
|
6877
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-card orion-admin-meta-table", children: [
|
|
6878
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6879
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: "Form" }),
|
|
6880
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: relatedFormID ? /* @__PURE__ */ jsx31(Link5, { href: formPath, children: formTitle }) : formTitle })
|
|
6881
|
+
] }),
|
|
6882
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6883
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: "Primary contact" }),
|
|
6884
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: identity.name || identity.email || "Unknown" })
|
|
6885
|
+
] }),
|
|
6886
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6887
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: "Email" }),
|
|
6888
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: identity.email || "Not provided" })
|
|
6889
|
+
] }),
|
|
6890
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6891
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: "Submission ID" }),
|
|
6892
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: submissionID })
|
|
6893
|
+
] }),
|
|
6894
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-meta-row", children: [
|
|
6895
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-label", children: "Form slug" }),
|
|
6896
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-meta-value", children: typeof doc.formSlug === "string" && doc.formSlug.trim().length > 0 ? doc.formSlug : "Unavailable" })
|
|
6897
|
+
] })
|
|
6898
|
+
] }),
|
|
6899
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-card", children: [
|
|
6900
|
+
/* @__PURE__ */ jsx31("strong", { children: "Attached uploads" }),
|
|
6901
|
+
/* @__PURE__ */ jsx31("span", { children: "Files linked to this response remain inside the Studio workspace." }),
|
|
6902
|
+
/* @__PURE__ */ jsx31("div", { style: { display: "grid", gap: "0.75rem", marginTop: "1rem" }, children: uploads.length > 0 ? uploads.map((upload) => {
|
|
6903
|
+
const uploadID = typeof upload.id === "string" || typeof upload.id === "number" ? String(upload.id) : "";
|
|
6904
|
+
if (!uploadID) return null;
|
|
6905
|
+
const uploadPath = resolveAdminPath(adminBasePath, `/forms/uploads/${uploadID}`);
|
|
6906
|
+
const meta = [formatFileSize2(upload.filesize), typeof upload.mimeType === "string" ? upload.mimeType : null].filter(Boolean).join(" \xB7 ");
|
|
6907
|
+
return /* @__PURE__ */ jsxs28(Link5, { className: "orion-admin-list-item", href: uploadPath, children: [
|
|
6908
|
+
/* @__PURE__ */ jsxs28("div", { children: [
|
|
6909
|
+
/* @__PURE__ */ jsx31("strong", { children: typeof upload.filename === "string" && upload.filename.trim().length > 0 ? upload.filename : `Upload ${uploadID}` }),
|
|
6910
|
+
/* @__PURE__ */ jsx31("div", { className: "orion-admin-list-meta", children: meta || "Open file details" })
|
|
6911
|
+
] }),
|
|
6912
|
+
/* @__PURE__ */ jsx31("span", { className: "orion-admin-action-button orion-admin-action-button--ghost", children: "Open" })
|
|
6913
|
+
] }, uploadID);
|
|
6914
|
+
}) : /* @__PURE__ */ jsxs28("div", { className: "orion-admin-empty-state", children: [
|
|
6915
|
+
/* @__PURE__ */ jsx31("strong", { children: "No files attached" }),
|
|
6916
|
+
/* @__PURE__ */ jsx31("span", { children: "This response did not include any uploads." })
|
|
6917
|
+
] }) })
|
|
6918
|
+
] }),
|
|
6919
|
+
confirmDelete ? /* @__PURE__ */ jsxs28("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
|
|
6920
|
+
/* @__PURE__ */ jsx31("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this submission?" }),
|
|
6921
|
+
/* @__PURE__ */ jsx31("p", { className: "orion-admin-list-meta", style: { margin: 0 }, children: "This action cannot be undone and will remove the stored response." }),
|
|
6922
|
+
/* @__PURE__ */ jsxs28("div", { className: "orion-admin-inline-actions", children: [
|
|
6923
|
+
/* @__PURE__ */ jsx31("button", { disabled: deleting, onClick: deleteSubmission, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
|
|
6924
|
+
/* @__PURE__ */ jsx31("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
|
|
6925
|
+
] })
|
|
6926
|
+
] }) : /* @__PURE__ */ jsx31(
|
|
6927
|
+
"button",
|
|
6928
|
+
{
|
|
6929
|
+
className: "orion-admin-action-button",
|
|
6930
|
+
onClick: () => setConfirmDelete(true),
|
|
6931
|
+
style: { background: "#b42318" },
|
|
6932
|
+
type: "button",
|
|
6933
|
+
children: "Delete Submission"
|
|
6934
|
+
}
|
|
6935
|
+
)
|
|
6936
|
+
] })
|
|
6937
|
+
] })
|
|
6938
|
+
] }) : null
|
|
6939
|
+
]
|
|
6940
|
+
}
|
|
6941
|
+
) });
|
|
6942
|
+
}
|
|
6943
|
+
|
|
6944
|
+
// src/admin/components/studio/AdminStudioFormUploadView.tsx
|
|
6945
|
+
import { useEffect as useEffect20, useMemo as useMemo16, useState as useState22 } from "react";
|
|
6946
|
+
import { Fragment as Fragment7, jsx as jsx32, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
6947
|
+
var previewStyle = {
|
|
6948
|
+
borderRadius: 14,
|
|
6949
|
+
display: "block",
|
|
6950
|
+
maxHeight: "28rem",
|
|
6951
|
+
objectFit: "contain",
|
|
6952
|
+
width: "100%"
|
|
6953
|
+
};
|
|
6954
|
+
function getUploadIDFromPathname(pathname) {
|
|
6955
|
+
return getIDFromPathname(pathname, "/forms/uploads/");
|
|
6956
|
+
}
|
|
6957
|
+
function AdminStudioFormUploadView(props) {
|
|
6958
|
+
const formUploadsCollectionSlug = getPropString14(props, "formUploadsCollectionSlug", "form-uploads");
|
|
6959
|
+
const adminBasePath = useAdminBasePath();
|
|
6960
|
+
const formsPath = resolveAdminPath(adminBasePath, "/forms");
|
|
6961
|
+
const uploadIDFromParams = useMemo16(() => getParam3(props.params, "id"), [props.params]);
|
|
6962
|
+
const [uploadID, setUploadID] = useState22(uploadIDFromParams);
|
|
6963
|
+
const [didResolvePathFallback, setDidResolvePathFallback] = useState22(false);
|
|
6964
|
+
const [doc, setDoc] = useState22(null);
|
|
6965
|
+
const [loading, setLoading] = useState22(true);
|
|
6966
|
+
const [error, setError] = useState22(null);
|
|
6967
|
+
const [savedMessage, setSavedMessage] = useState22(null);
|
|
6968
|
+
const [saving, setSaving] = useState22(false);
|
|
6969
|
+
const [confirmDelete, setConfirmDelete] = useState22(false);
|
|
6970
|
+
const [deleting, setDeleting] = useState22(false);
|
|
6971
|
+
useEffect20(() => {
|
|
6972
|
+
if (uploadIDFromParams) {
|
|
6973
|
+
setUploadID(uploadIDFromParams);
|
|
6974
|
+
setDidResolvePathFallback(true);
|
|
6975
|
+
return;
|
|
6976
|
+
}
|
|
6977
|
+
if (typeof window !== "undefined") {
|
|
6978
|
+
setUploadID(getUploadIDFromPathname(window.location.pathname));
|
|
6979
|
+
}
|
|
6980
|
+
setDidResolvePathFallback(true);
|
|
6981
|
+
}, [uploadIDFromParams]);
|
|
6982
|
+
const loadDoc = async (id) => {
|
|
6983
|
+
setLoading(true);
|
|
6984
|
+
setError(null);
|
|
6985
|
+
try {
|
|
6986
|
+
const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(id)}?depth=0&draft=true`, {
|
|
6987
|
+
credentials: "include"
|
|
6988
|
+
});
|
|
6989
|
+
if (!response.ok) {
|
|
6990
|
+
throw new Error(`Failed to load upload (${response.status}).`);
|
|
6991
|
+
}
|
|
6992
|
+
const nextDoc = await response.json();
|
|
6993
|
+
setDoc(nextDoc);
|
|
6994
|
+
} catch (loadError) {
|
|
6995
|
+
setError(loadError instanceof Error ? loadError.message : "Failed to load upload.");
|
|
6996
|
+
setDoc(null);
|
|
6997
|
+
} finally {
|
|
6998
|
+
setLoading(false);
|
|
6999
|
+
}
|
|
7000
|
+
};
|
|
7001
|
+
useEffect20(() => {
|
|
7002
|
+
if (!uploadID) {
|
|
7003
|
+
return;
|
|
7004
|
+
}
|
|
7005
|
+
void loadDoc(uploadID);
|
|
7006
|
+
}, [formUploadsCollectionSlug, uploadID]);
|
|
7007
|
+
const save = async (event) => {
|
|
7008
|
+
event.preventDefault();
|
|
7009
|
+
if (!uploadID) {
|
|
7010
|
+
return;
|
|
7011
|
+
}
|
|
7012
|
+
setSaving(true);
|
|
7013
|
+
setError(null);
|
|
7014
|
+
setSavedMessage(null);
|
|
7015
|
+
try {
|
|
7016
|
+
const formData = new FormData(event.currentTarget);
|
|
7017
|
+
const alt = String(formData.get("alt") || "").trim();
|
|
7018
|
+
const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
|
|
7019
|
+
body: JSON.stringify({ alt }),
|
|
7020
|
+
credentials: "include",
|
|
7021
|
+
headers: {
|
|
7022
|
+
"Content-Type": "application/json"
|
|
7023
|
+
},
|
|
7024
|
+
method: "PATCH"
|
|
7025
|
+
});
|
|
7026
|
+
if (!response.ok) {
|
|
7027
|
+
throw new Error(`Failed to save upload (${response.status}).`);
|
|
7028
|
+
}
|
|
7029
|
+
const nextDoc = await response.json();
|
|
7030
|
+
setDoc(nextDoc);
|
|
7031
|
+
setSavedMessage("Saved.");
|
|
7032
|
+
} catch (saveError) {
|
|
7033
|
+
setError(saveError instanceof Error ? saveError.message : "Failed to save upload.");
|
|
7034
|
+
} finally {
|
|
7035
|
+
setSaving(false);
|
|
7036
|
+
}
|
|
7037
|
+
};
|
|
7038
|
+
const deleteUpload = async () => {
|
|
7039
|
+
if (!uploadID) {
|
|
7040
|
+
return;
|
|
7041
|
+
}
|
|
7042
|
+
setDeleting(true);
|
|
7043
|
+
setError(null);
|
|
7044
|
+
try {
|
|
7045
|
+
const response = await fetch(`/api/${formUploadsCollectionSlug}/${encodeURIComponent(uploadID)}`, {
|
|
7046
|
+
credentials: "include",
|
|
7047
|
+
method: "DELETE"
|
|
7048
|
+
});
|
|
7049
|
+
if (!response.ok) {
|
|
7050
|
+
throw new Error(`Failed to delete upload (${response.status}).`);
|
|
7051
|
+
}
|
|
7052
|
+
window.location.assign(formsPath);
|
|
7053
|
+
} catch (deleteError) {
|
|
7054
|
+
setError(deleteError instanceof Error ? deleteError.message : "Failed to delete upload.");
|
|
7055
|
+
setDeleting(false);
|
|
7056
|
+
}
|
|
7057
|
+
};
|
|
7058
|
+
if (!uploadID && !didResolvePathFallback) {
|
|
7059
|
+
return /* @__PURE__ */ jsx32(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx32(
|
|
7060
|
+
AdminPage,
|
|
7061
|
+
{
|
|
7062
|
+
breadcrumbs: [
|
|
7063
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
7064
|
+
{ label: "Forms", href: formsPath },
|
|
7065
|
+
{ label: "Upload" }
|
|
7066
|
+
],
|
|
7067
|
+
description: "Loading upload workspace...",
|
|
7068
|
+
title: "Upload",
|
|
7069
|
+
children: /* @__PURE__ */ jsx32(Fragment7, {})
|
|
7070
|
+
}
|
|
7071
|
+
) });
|
|
7072
|
+
}
|
|
7073
|
+
const filename = doc && typeof doc.filename === "string" && doc.filename.trim().length > 0 ? doc.filename : uploadID ? `Upload ${uploadID}` : "Upload";
|
|
7074
|
+
const mimeType = doc && typeof doc.mimeType === "string" ? doc.mimeType : "";
|
|
7075
|
+
const sourceURL = doc && typeof doc.url === "string" && doc.url.trim().length > 0 ? doc.url : null;
|
|
7076
|
+
const canPreview = Boolean(sourceURL && mimeType.startsWith("image/"));
|
|
7077
|
+
const createdAt = doc?.createdAt ?? doc?.updatedAt;
|
|
7078
|
+
return /* @__PURE__ */ jsx32(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs29(
|
|
7079
|
+
AdminPage,
|
|
7080
|
+
{
|
|
7081
|
+
breadcrumbs: [
|
|
7082
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
7083
|
+
{ label: "Forms", href: formsPath },
|
|
7084
|
+
{ label: filename }
|
|
7085
|
+
],
|
|
7086
|
+
description: "Review file metadata, update alt text, and remove private uploads from Studio.",
|
|
7087
|
+
title: "Upload",
|
|
7088
|
+
children: [
|
|
7089
|
+
loading ? /* @__PURE__ */ jsx32("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
7090
|
+
error ? /* @__PURE__ */ jsx32("div", { className: "orion-admin-error", children: error }) : null,
|
|
7091
|
+
savedMessage ? /* @__PURE__ */ jsx32("div", { className: "orion-admin-success", children: savedMessage }) : null,
|
|
7092
|
+
!loading && !error && doc && uploadID ? /* @__PURE__ */ jsxs29("div", { className: "orion-admin-grid", style: { alignItems: "start" }, children: [
|
|
7093
|
+
/* @__PURE__ */ jsxs29("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
7094
|
+
/* @__PURE__ */ jsx32("div", { className: "orion-admin-card", children: canPreview && sourceURL ? /* @__PURE__ */ jsx32("img", { alt: filename, src: sourceURL, style: previewStyle }) : /* @__PURE__ */ jsxs29(Fragment7, { children: [
|
|
7095
|
+
/* @__PURE__ */ jsx32("strong", { children: "No inline preview" }),
|
|
7096
|
+
/* @__PURE__ */ jsx32("span", { children: mimeType ? `Preview unavailable for ${mimeType}.` : "Preview unavailable for this file." })
|
|
7097
|
+
] }) }),
|
|
7098
|
+
sourceURL ? /* @__PURE__ */ jsx32("a", { className: "orion-admin-action-button", href: sourceURL, rel: "noreferrer", target: "_blank", children: "Open File" }) : null
|
|
7099
|
+
] }),
|
|
7100
|
+
/* @__PURE__ */ jsxs29("div", { style: { display: "grid", gap: "0.8rem" }, children: [
|
|
7101
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-card orion-admin-meta-table", children: [
|
|
7102
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-meta-row", children: [
|
|
7103
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-label", children: "Filename" }),
|
|
7104
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-value", children: filename })
|
|
7105
|
+
] }),
|
|
7106
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-meta-row", children: [
|
|
7107
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-label", children: "File size" }),
|
|
7108
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-value", children: formatFileSize2(doc.filesize) || "Unavailable" })
|
|
7109
|
+
] }),
|
|
7110
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-meta-row", children: [
|
|
7111
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-label", children: "Type" }),
|
|
7112
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-value", children: mimeType || "Unavailable" })
|
|
7113
|
+
] }),
|
|
7114
|
+
typeof doc.width === "number" && typeof doc.height === "number" ? /* @__PURE__ */ jsxs29("div", { className: "orion-admin-meta-row", children: [
|
|
7115
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-label", children: "Dimensions" }),
|
|
7116
|
+
/* @__PURE__ */ jsxs29("span", { className: "orion-admin-meta-value", children: [
|
|
7117
|
+
doc.width,
|
|
7118
|
+
" x ",
|
|
7119
|
+
doc.height,
|
|
7120
|
+
"px"
|
|
7121
|
+
] })
|
|
7122
|
+
] }) : null,
|
|
7123
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-meta-row", children: [
|
|
7124
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-label", children: "Uploaded" }),
|
|
7125
|
+
/* @__PURE__ */ jsx32("span", { className: "orion-admin-meta-value", children: formatDate2(createdAt) })
|
|
7126
|
+
] })
|
|
7127
|
+
] }),
|
|
7128
|
+
/* @__PURE__ */ jsxs29("form", { className: "orion-admin-form", onSubmit: save, children: [
|
|
7129
|
+
/* @__PURE__ */ jsx32("strong", { children: "Asset details" }),
|
|
7130
|
+
/* @__PURE__ */ jsxs29("label", { children: [
|
|
7131
|
+
"Alt text",
|
|
7132
|
+
/* @__PURE__ */ jsx32("input", { defaultValue: typeof doc.alt === "string" ? doc.alt : "", name: "alt", type: "text" })
|
|
7133
|
+
] }),
|
|
7134
|
+
/* @__PURE__ */ jsx32("button", { disabled: saving, type: "submit", children: saving ? "Saving..." : "Save Upload" })
|
|
7135
|
+
] }),
|
|
7136
|
+
confirmDelete ? /* @__PURE__ */ jsxs29("div", { className: "orion-admin-form", style: { borderColor: "#b42318" }, children: [
|
|
7137
|
+
/* @__PURE__ */ jsx32("p", { style: { fontWeight: 700, margin: 0 }, children: "Delete this upload?" }),
|
|
7138
|
+
/* @__PURE__ */ jsx32("p", { className: "orion-admin-list-meta", style: { margin: 0 }, children: "This removes the stored file and any linked submission attachment references." }),
|
|
7139
|
+
/* @__PURE__ */ jsxs29("div", { className: "orion-admin-inline-actions", children: [
|
|
7140
|
+
/* @__PURE__ */ jsx32("button", { disabled: deleting, onClick: deleteUpload, type: "button", children: deleting ? "Deleting..." : "Yes, Delete" }),
|
|
7141
|
+
/* @__PURE__ */ jsx32("button", { onClick: () => setConfirmDelete(false), type: "button", children: "Cancel" })
|
|
7142
|
+
] })
|
|
7143
|
+
] }) : /* @__PURE__ */ jsx32(
|
|
7144
|
+
"button",
|
|
7145
|
+
{
|
|
7146
|
+
className: "orion-admin-action-button",
|
|
7147
|
+
onClick: () => setConfirmDelete(true),
|
|
7148
|
+
style: { background: "#b42318" },
|
|
7149
|
+
type: "button",
|
|
7150
|
+
children: "Delete Upload"
|
|
7151
|
+
}
|
|
7152
|
+
)
|
|
7153
|
+
] })
|
|
7154
|
+
] }) : null
|
|
7155
|
+
]
|
|
7156
|
+
}
|
|
7157
|
+
) });
|
|
7158
|
+
}
|
|
7159
|
+
|
|
7160
|
+
// src/admin/components/studio/AdminStudioToolsView.tsx
|
|
7161
|
+
import { useEffect as useEffect21, useState as useState23 } from "react";
|
|
7162
|
+
import { useAuth as useAuth6 } from "@payloadcms/ui";
|
|
7163
|
+
import { jsx as jsx33, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
7164
|
+
var userRoles = ["admin", "developer", "editor", "client"];
|
|
7165
|
+
var hasAdminAccess3 = (user) => {
|
|
7166
|
+
if (!user || typeof user !== "object") return false;
|
|
7167
|
+
const role = user.role;
|
|
7168
|
+
return typeof role === "string" && (role === "admin" || role === "developer");
|
|
7169
|
+
};
|
|
7170
|
+
var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
|
|
7171
|
+
function AdminStudioToolsView(props) {
|
|
7172
|
+
const { user } = useAuth6();
|
|
7173
|
+
const adminBasePath = useAdminBasePath();
|
|
7174
|
+
const [docs, setDocs] = useState23([]);
|
|
7175
|
+
const [loading, setLoading] = useState23(true);
|
|
7176
|
+
const [error, setError] = useState23(null);
|
|
7177
|
+
const [savedMessage, setSavedMessage] = useState23(null);
|
|
7178
|
+
const [createSubmitting, setCreateSubmitting] = useState23(false);
|
|
7179
|
+
const [updatingUserID, setUpdatingUserID] = useState23(null);
|
|
7180
|
+
if (!hasAdminAccess3(user)) {
|
|
7181
|
+
return /* @__PURE__ */ jsx33(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx33(
|
|
7182
|
+
AdminPage,
|
|
7183
|
+
{
|
|
7184
|
+
breadcrumbs: [
|
|
7185
|
+
{ label: "Dashboard", href: adminBasePath },
|
|
7186
|
+
{ label: "Admin Tools" }
|
|
7187
|
+
],
|
|
7188
|
+
description: "You do not have access to this section.",
|
|
5726
7189
|
title: "Admin Tools",
|
|
5727
|
-
children: /* @__PURE__ */
|
|
5728
|
-
/* @__PURE__ */
|
|
5729
|
-
/* @__PURE__ */
|
|
7190
|
+
children: /* @__PURE__ */ jsxs30("div", { className: "orion-admin-card", children: [
|
|
7191
|
+
/* @__PURE__ */ jsx33("strong", { children: "Access denied" }),
|
|
7192
|
+
/* @__PURE__ */ jsx33("span", { children: "This section is restricted to administrator and developer accounts." })
|
|
5730
7193
|
] })
|
|
5731
7194
|
}
|
|
5732
7195
|
) });
|
|
@@ -5755,16 +7218,17 @@ function AdminStudioToolsView(props) {
|
|
|
5755
7218
|
setLoading(false);
|
|
5756
7219
|
}
|
|
5757
7220
|
};
|
|
5758
|
-
|
|
7221
|
+
useEffect21(() => {
|
|
5759
7222
|
void loadUsers();
|
|
5760
7223
|
}, []);
|
|
5761
7224
|
const createUser = async (event) => {
|
|
5762
7225
|
event.preventDefault();
|
|
7226
|
+
const form = event.currentTarget;
|
|
5763
7227
|
setCreateSubmitting(true);
|
|
5764
7228
|
setError(null);
|
|
5765
7229
|
setSavedMessage(null);
|
|
5766
7230
|
try {
|
|
5767
|
-
const formData = new FormData(
|
|
7231
|
+
const formData = new FormData(form);
|
|
5768
7232
|
const email = String(formData.get("email") || "").trim();
|
|
5769
7233
|
const password = String(formData.get("password") || "");
|
|
5770
7234
|
const fullName = String(formData.get("fullName") || "").trim();
|
|
@@ -5788,7 +7252,7 @@ function AdminStudioToolsView(props) {
|
|
|
5788
7252
|
if (!response.ok) {
|
|
5789
7253
|
throw new Error(`Failed to create user (${response.status}).`);
|
|
5790
7254
|
}
|
|
5791
|
-
|
|
7255
|
+
form.reset();
|
|
5792
7256
|
await loadUsers();
|
|
5793
7257
|
setSavedMessage("User created.");
|
|
5794
7258
|
} catch (createError) {
|
|
@@ -5826,7 +7290,7 @@ function AdminStudioToolsView(props) {
|
|
|
5826
7290
|
setUpdatingUserID(null);
|
|
5827
7291
|
}
|
|
5828
7292
|
};
|
|
5829
|
-
return /* @__PURE__ */
|
|
7293
|
+
return /* @__PURE__ */ jsx33(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs30(
|
|
5830
7294
|
AdminPage,
|
|
5831
7295
|
{
|
|
5832
7296
|
breadcrumbs: [
|
|
@@ -5836,53 +7300,44 @@ function AdminStudioToolsView(props) {
|
|
|
5836
7300
|
description: "Manage users and fallback links to Payload native admin.",
|
|
5837
7301
|
title: "Admin Tools",
|
|
5838
7302
|
children: [
|
|
5839
|
-
/* @__PURE__ */
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
/* @__PURE__ */
|
|
5844
|
-
/* @__PURE__ */ jsxs27("label", { children: [
|
|
7303
|
+
error ? /* @__PURE__ */ jsx33("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
|
|
7304
|
+
savedMessage ? /* @__PURE__ */ jsx33("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
|
|
7305
|
+
/* @__PURE__ */ jsxs30("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
|
|
7306
|
+
/* @__PURE__ */ jsx33("strong", { children: "Create User" }),
|
|
7307
|
+
/* @__PURE__ */ jsxs30("label", { children: [
|
|
5845
7308
|
"Email",
|
|
5846
|
-
/* @__PURE__ */
|
|
7309
|
+
/* @__PURE__ */ jsx33("input", { name: "email", required: true, type: "email" })
|
|
5847
7310
|
] }),
|
|
5848
|
-
/* @__PURE__ */
|
|
7311
|
+
/* @__PURE__ */ jsxs30("label", { children: [
|
|
5849
7312
|
"Full Name",
|
|
5850
|
-
/* @__PURE__ */
|
|
7313
|
+
/* @__PURE__ */ jsx33("input", { name: "fullName", type: "text" })
|
|
5851
7314
|
] }),
|
|
5852
|
-
/* @__PURE__ */
|
|
7315
|
+
/* @__PURE__ */ jsxs30("label", { children: [
|
|
5853
7316
|
"Password",
|
|
5854
|
-
/* @__PURE__ */
|
|
7317
|
+
/* @__PURE__ */ jsx33("input", { name: "password", required: true, type: "password" })
|
|
5855
7318
|
] }),
|
|
5856
|
-
/* @__PURE__ */
|
|
7319
|
+
/* @__PURE__ */ jsxs30("label", { children: [
|
|
5857
7320
|
"Role",
|
|
5858
|
-
/* @__PURE__ */
|
|
5859
|
-
/* @__PURE__ */ jsx30("option", { value: "admin", children: "admin" }),
|
|
5860
|
-
/* @__PURE__ */ jsx30("option", { value: "editor", children: "editor" }),
|
|
5861
|
-
/* @__PURE__ */ jsx30("option", { value: "client", children: "client" })
|
|
5862
|
-
] })
|
|
7321
|
+
/* @__PURE__ */ jsx33("select", { defaultValue: "editor", name: "role", children: userRoles.map((role) => /* @__PURE__ */ jsx33("option", { value: role, children: role }, role)) })
|
|
5863
7322
|
] }),
|
|
5864
|
-
/* @__PURE__ */
|
|
7323
|
+
/* @__PURE__ */ jsx33("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
|
|
5865
7324
|
] }),
|
|
5866
|
-
loading ? /* @__PURE__ */
|
|
5867
|
-
/* @__PURE__ */
|
|
7325
|
+
loading ? /* @__PURE__ */ jsx33("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
|
|
7326
|
+
/* @__PURE__ */ jsx33("div", { className: "orion-admin-list", children: docs.map((doc) => {
|
|
5868
7327
|
const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
|
|
5869
7328
|
if (!id) return null;
|
|
5870
7329
|
const email = typeof doc.email === "string" ? doc.email : `user-${id}`;
|
|
5871
7330
|
const fullName = typeof doc.fullName === "string" ? doc.fullName : "";
|
|
5872
7331
|
const currentRole = typeof doc.role === "string" ? normalizeRole(doc.role) : "editor";
|
|
5873
|
-
return /* @__PURE__ */
|
|
5874
|
-
/* @__PURE__ */
|
|
5875
|
-
/* @__PURE__ */
|
|
5876
|
-
/* @__PURE__ */
|
|
7332
|
+
return /* @__PURE__ */ jsxs30("div", { className: "orion-admin-list-item", children: [
|
|
7333
|
+
/* @__PURE__ */ jsxs30("div", { children: [
|
|
7334
|
+
/* @__PURE__ */ jsx33("strong", { children: email }),
|
|
7335
|
+
/* @__PURE__ */ jsx33("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
|
|
5877
7336
|
] }),
|
|
5878
|
-
/* @__PURE__ */
|
|
5879
|
-
/* @__PURE__ */
|
|
5880
|
-
/* @__PURE__ */
|
|
5881
|
-
|
|
5882
|
-
/* @__PURE__ */ jsx30("option", { value: "editor", children: "editor" }),
|
|
5883
|
-
/* @__PURE__ */ jsx30("option", { value: "client", children: "client" })
|
|
5884
|
-
] }),
|
|
5885
|
-
/* @__PURE__ */ jsx30("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
|
|
7337
|
+
/* @__PURE__ */ jsxs30("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
|
|
7338
|
+
/* @__PURE__ */ jsx33("input", { name: "id", type: "hidden", value: id }),
|
|
7339
|
+
/* @__PURE__ */ jsx33("select", { defaultValue: currentRole, name: "role", children: userRoles.map((role) => /* @__PURE__ */ jsx33("option", { value: role, children: role }, role)) }),
|
|
7340
|
+
/* @__PURE__ */ jsx33("button", { disabled: updatingUserID === id, type: "submit", children: updatingUserID === id ? "Updating..." : "Update" })
|
|
5886
7341
|
] })
|
|
5887
7342
|
] }, id);
|
|
5888
7343
|
}) })
|
|
@@ -5893,14 +7348,14 @@ function AdminStudioToolsView(props) {
|
|
|
5893
7348
|
|
|
5894
7349
|
// src/admin/components/studio/OpenInStudioMenuItem.tsx
|
|
5895
7350
|
import { useDocumentInfo } from "@payloadcms/ui";
|
|
5896
|
-
import { jsx as
|
|
7351
|
+
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
5897
7352
|
function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
|
|
5898
7353
|
const documentInfo = useDocumentInfo();
|
|
5899
7354
|
const id = documentInfo?.id;
|
|
5900
7355
|
if (!id) {
|
|
5901
7356
|
return null;
|
|
5902
7357
|
}
|
|
5903
|
-
return /* @__PURE__ */
|
|
7358
|
+
return /* @__PURE__ */ jsx34(
|
|
5904
7359
|
"a",
|
|
5905
7360
|
{
|
|
5906
7361
|
href: `${pagesPathBase}/${id}`,
|
|
@@ -5919,19 +7374,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
|
|
|
5919
7374
|
}
|
|
5920
7375
|
|
|
5921
7376
|
// src/admin/components/studio/PageEditRedirectToStudio.tsx
|
|
5922
|
-
import { useEffect as
|
|
7377
|
+
import { useEffect as useEffect22 } from "react";
|
|
5923
7378
|
import { useDocumentInfo as useDocumentInfo2 } from "@payloadcms/ui";
|
|
5924
|
-
import { jsx as
|
|
7379
|
+
import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5925
7380
|
function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
|
|
5926
7381
|
const documentInfo = useDocumentInfo2();
|
|
5927
7382
|
const id = documentInfo?.id;
|
|
5928
|
-
|
|
7383
|
+
useEffect22(() => {
|
|
5929
7384
|
if (!id) {
|
|
5930
7385
|
return;
|
|
5931
7386
|
}
|
|
5932
7387
|
window.location.replace(`${pagesPathBase}/${id}`);
|
|
5933
7388
|
}, [id, pagesPathBase]);
|
|
5934
|
-
return /* @__PURE__ */
|
|
7389
|
+
return /* @__PURE__ */ jsxs31(
|
|
5935
7390
|
"div",
|
|
5936
7391
|
{
|
|
5937
7392
|
style: {
|
|
@@ -5943,18 +7398,61 @@ function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
|
|
|
5943
7398
|
minHeight: "50vh"
|
|
5944
7399
|
},
|
|
5945
7400
|
children: [
|
|
5946
|
-
/* @__PURE__ */
|
|
5947
|
-
/* @__PURE__ */
|
|
5948
|
-
id ? /* @__PURE__ */
|
|
7401
|
+
/* @__PURE__ */ jsx35("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
|
|
7402
|
+
/* @__PURE__ */ jsx35("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
|
|
7403
|
+
id ? /* @__PURE__ */ jsx35("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ jsx35("a", { href: pagesPathBase, children: "Open Pages" })
|
|
7404
|
+
]
|
|
7405
|
+
}
|
|
7406
|
+
);
|
|
7407
|
+
}
|
|
7408
|
+
|
|
7409
|
+
// src/admin/components/studio/StudioDocumentRedirect.tsx
|
|
7410
|
+
import { useEffect as useEffect23 } from "react";
|
|
7411
|
+
import { useDocumentInfo as useDocumentInfo3 } from "@payloadcms/ui";
|
|
7412
|
+
import { jsx as jsx36, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
7413
|
+
function StudioDocumentRedirect({
|
|
7414
|
+
description = "Redirecting to the Studio view.",
|
|
7415
|
+
emptyHref,
|
|
7416
|
+
emptyLabel = "Open Studio",
|
|
7417
|
+
pathBase = "/forms",
|
|
7418
|
+
title = "Opening Studio..."
|
|
7419
|
+
}) {
|
|
7420
|
+
const adminBasePath = useAdminBasePath();
|
|
7421
|
+
const documentInfo = useDocumentInfo3();
|
|
7422
|
+
const id = documentInfo?.id;
|
|
7423
|
+
const fallbackHref = resolveAdminPath(adminBasePath, emptyHref || pathBase);
|
|
7424
|
+
useEffect23(() => {
|
|
7425
|
+
if (!id) {
|
|
7426
|
+
return;
|
|
7427
|
+
}
|
|
7428
|
+
const targetHref = resolveAdminPath(adminBasePath, `${pathBase}/${encodeURIComponent(String(id))}`);
|
|
7429
|
+
window.location.replace(targetHref);
|
|
7430
|
+
}, [adminBasePath, id, pathBase]);
|
|
7431
|
+
return /* @__PURE__ */ jsxs32(
|
|
7432
|
+
"div",
|
|
7433
|
+
{
|
|
7434
|
+
style: {
|
|
7435
|
+
alignItems: "center",
|
|
7436
|
+
display: "flex",
|
|
7437
|
+
flexDirection: "column",
|
|
7438
|
+
gap: "0.75rem",
|
|
7439
|
+
justifyContent: "center",
|
|
7440
|
+
minHeight: "50vh",
|
|
7441
|
+
textAlign: "center"
|
|
7442
|
+
},
|
|
7443
|
+
children: [
|
|
7444
|
+
/* @__PURE__ */ jsx36("h2", { style: { margin: 0 }, children: title }),
|
|
7445
|
+
/* @__PURE__ */ jsx36("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: description }),
|
|
7446
|
+
/* @__PURE__ */ jsx36("a", { href: fallbackHref, children: emptyLabel })
|
|
5949
7447
|
]
|
|
5950
7448
|
}
|
|
5951
7449
|
);
|
|
5952
7450
|
}
|
|
5953
7451
|
|
|
5954
7452
|
// src/admin/components/studio/StudioBackBreadcrumb.tsx
|
|
5955
|
-
import { useEffect as
|
|
7453
|
+
import { useEffect as useEffect24, useState as useState24 } from "react";
|
|
5956
7454
|
import { SetStepNav as SetStepNav5 } from "@payloadcms/ui";
|
|
5957
|
-
import { jsx as
|
|
7455
|
+
import { jsx as jsx37 } from "react/jsx-runtime";
|
|
5958
7456
|
var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
5959
7457
|
var buildNav = (pathname, adminBasePath) => {
|
|
5960
7458
|
if (pathname.includes("/globals/")) {
|
|
@@ -5999,8 +7497,8 @@ var buildNav = (pathname, adminBasePath) => {
|
|
|
5999
7497
|
};
|
|
6000
7498
|
function StudioBackBreadcrumb() {
|
|
6001
7499
|
const adminBasePath = useAdminBasePath();
|
|
6002
|
-
const [pathname, setPathname] =
|
|
6003
|
-
|
|
7500
|
+
const [pathname, setPathname] = useState24("");
|
|
7501
|
+
useEffect24(() => {
|
|
6004
7502
|
const update = () => setPathname(window.location.pathname);
|
|
6005
7503
|
update();
|
|
6006
7504
|
window.addEventListener("popstate", update);
|
|
@@ -6008,13 +7506,13 @@ function StudioBackBreadcrumb() {
|
|
|
6008
7506
|
}, []);
|
|
6009
7507
|
const nav = buildNav(pathname, adminBasePath);
|
|
6010
7508
|
if (!nav) return null;
|
|
6011
|
-
return /* @__PURE__ */
|
|
7509
|
+
return /* @__PURE__ */ jsx37(SetStepNav5, { nav });
|
|
6012
7510
|
}
|
|
6013
7511
|
|
|
6014
7512
|
// src/admin/components/studio/StudioContactFormRedirect.tsx
|
|
6015
|
-
import { useEffect as
|
|
6016
|
-
import { jsx as
|
|
6017
|
-
var
|
|
7513
|
+
import { useEffect as useEffect25 } from "react";
|
|
7514
|
+
import { jsx as jsx38, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
7515
|
+
var getPropString15 = (props, key, fallback) => {
|
|
6018
7516
|
if (!props || typeof props !== "object") return fallback;
|
|
6019
7517
|
const direct = props[key];
|
|
6020
7518
|
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
@@ -6027,13 +7525,13 @@ var getPropString14 = (props, key, fallback) => {
|
|
|
6027
7525
|
};
|
|
6028
7526
|
function StudioContactFormRedirect(props) {
|
|
6029
7527
|
const adminBasePath = useAdminBasePath();
|
|
6030
|
-
const studioContactFormPath =
|
|
7528
|
+
const studioContactFormPath = getPropString15(props, "studioContactFormPath", "/contact-form");
|
|
6031
7529
|
const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
|
|
6032
|
-
|
|
7530
|
+
useEffect25(() => {
|
|
6033
7531
|
if (window.location.pathname === targetPath) return;
|
|
6034
7532
|
window.location.replace(targetPath);
|
|
6035
7533
|
}, [targetPath]);
|
|
6036
|
-
return /* @__PURE__ */
|
|
7534
|
+
return /* @__PURE__ */ jsxs33(
|
|
6037
7535
|
"div",
|
|
6038
7536
|
{
|
|
6039
7537
|
style: {
|
|
@@ -6046,8 +7544,8 @@ function StudioContactFormRedirect(props) {
|
|
|
6046
7544
|
minHeight: "40vh"
|
|
6047
7545
|
},
|
|
6048
7546
|
children: [
|
|
6049
|
-
/* @__PURE__ */
|
|
6050
|
-
/* @__PURE__ */
|
|
7547
|
+
/* @__PURE__ */ jsx38("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
|
|
7548
|
+
/* @__PURE__ */ jsx38("a", { href: targetPath, children: "Continue" })
|
|
6051
7549
|
]
|
|
6052
7550
|
}
|
|
6053
7551
|
);
|
|
@@ -6058,6 +7556,9 @@ export {
|
|
|
6058
7556
|
AdminStudioContactFormView,
|
|
6059
7557
|
AdminStudioDashboard,
|
|
6060
7558
|
AdminStudioFooterGlobalView,
|
|
7559
|
+
AdminStudioFormDetailView,
|
|
7560
|
+
AdminStudioFormSubmissionView,
|
|
7561
|
+
AdminStudioFormUploadView,
|
|
6061
7562
|
AdminStudioFormsView,
|
|
6062
7563
|
AdminStudioGlobalsView,
|
|
6063
7564
|
AdminStudioHeaderGlobalView,
|
|
@@ -6083,6 +7584,7 @@ export {
|
|
|
6083
7584
|
StatusBadge,
|
|
6084
7585
|
StudioBackBreadcrumb,
|
|
6085
7586
|
StudioContactFormRedirect,
|
|
7587
|
+
StudioDocumentRedirect,
|
|
6086
7588
|
StudioSectionLayout,
|
|
6087
7589
|
ThemeProvider,
|
|
6088
7590
|
ThemeSwitcher,
|