@orion-studios/payload-studio 0.6.0-beta.8 → 0.7.0

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.
Files changed (66) hide show
  1. package/README.md +6 -1
  2. package/bin/init.js +329 -0
  3. package/dist/admin/client.js +2106 -585
  4. package/dist/admin/client.mjs +2161 -653
  5. package/dist/admin/index.d.mts +2 -2
  6. package/dist/admin/index.d.ts +2 -2
  7. package/dist/admin/index.js +201 -37
  8. package/dist/admin/index.mjs +2 -2
  9. package/dist/admin-app/client.js +14 -5
  10. package/dist/admin-app/client.mjs +1 -1
  11. package/dist/admin-app/index.d.mts +2 -2
  12. package/dist/admin-app/index.d.ts +2 -2
  13. package/dist/admin-app/styles.css +361 -41
  14. package/dist/admin.css +98 -2
  15. package/dist/blocks/index.mjs +1 -2
  16. package/dist/builder-v2/client.d.mts +18 -0
  17. package/dist/builder-v2/client.d.ts +18 -0
  18. package/dist/builder-v2/client.js +4287 -0
  19. package/dist/builder-v2/client.mjs +4162 -0
  20. package/dist/builder-v2/index.d.mts +249 -0
  21. package/dist/builder-v2/index.d.ts +249 -0
  22. package/dist/builder-v2/index.js +836 -0
  23. package/dist/builder-v2/index.mjs +786 -0
  24. package/dist/builder-v2/styles.css +2705 -0
  25. package/dist/{chunk-PF3EBZXF.mjs → chunk-7ZMXZRBP.mjs} +39 -3
  26. package/dist/{chunk-XKUTZ7IU.mjs → chunk-DTHBPJXU.mjs} +246 -25
  27. package/dist/{chunk-JQAHXYAM.mjs → chunk-KMYMSR7W.mjs} +163 -3
  28. package/dist/{chunk-5FNTVRCR.mjs → chunk-MMJNHBOF.mjs} +204 -40
  29. package/dist/{chunk-KPIX7OSV.mjs → chunk-NF37A575.mjs} +14 -5
  30. package/dist/{chunk-OTHERBGX.mjs → chunk-OF6BATTO.mjs} +57 -112
  31. package/dist/chunk-VA545CHJ.mjs +202 -0
  32. package/dist/forms/index.d.mts +25 -0
  33. package/dist/forms/index.d.ts +25 -0
  34. package/dist/forms/index.js +237 -0
  35. package/dist/forms/index.mjs +25 -0
  36. package/dist/forms/server.d.mts +35 -0
  37. package/dist/forms/server.d.ts +35 -0
  38. package/dist/forms/server.js +442 -0
  39. package/dist/forms/server.mjs +228 -0
  40. package/dist/{index-Crx_MtPw.d.ts → index-0xXWuOuz.d.ts} +38 -6
  41. package/dist/{index-Cv-6qnrw.d.mts → index-BU82akSL.d.mts} +38 -6
  42. package/dist/{index-DyMmaRfI.d.mts → index-BbTcimgH.d.mts} +5 -2
  43. package/dist/{index-D8BNfUJb.d.mts → index-Cen-9wcc.d.mts} +17 -5
  44. package/dist/{index-52HdVLQq.d.ts → index-DAdN56fM.d.ts} +1 -1
  45. package/dist/{index-QPDAedIX.d.ts → index-DV-nW43e.d.ts} +5 -2
  46. package/dist/{index-DEQC3Dwj.d.mts → index-G_uTNffQ.d.mts} +1 -1
  47. package/dist/{index-DD_E2UfJ.d.ts → index-gxcMPpm-.d.ts} +17 -5
  48. package/dist/index.d.mts +5 -5
  49. package/dist/index.d.ts +5 -5
  50. package/dist/index.js +533 -172
  51. package/dist/index.mjs +10 -11
  52. package/dist/nextjs/index.d.mts +1 -1
  53. package/dist/nextjs/index.d.ts +1 -1
  54. package/dist/nextjs/index.js +95 -114
  55. package/dist/nextjs/index.mjs +2 -2
  56. package/dist/{sitePreviewTypes-BkHCWxNW.d.mts → sitePreviewTypes-BrJwGzJj.d.mts} +1 -1
  57. package/dist/{sitePreviewTypes-BkHCWxNW.d.ts → sitePreviewTypes-BrJwGzJj.d.ts} +1 -1
  58. package/dist/studio-pages/builder.css +66 -5
  59. package/dist/studio-pages/client.js +618 -73
  60. package/dist/studio-pages/client.mjs +641 -96
  61. package/dist/studio-pages/index.d.mts +1 -1
  62. package/dist/studio-pages/index.d.ts +1 -1
  63. package/dist/studio-pages/index.js +1893 -24
  64. package/dist/studio-pages/index.mjs +11 -3
  65. package/package.json +38 -3
  66. package/dist/chunk-OQSEJXC4.mjs +0 -166
@@ -9,7 +9,7 @@ import {
9
9
  SiteFooterPreview,
10
10
  adminNavIcons,
11
11
  buildAdminPageLinkOptions
12
- } from "../chunk-KPIX7OSV.mjs";
12
+ } from "../chunk-NF37A575.mjs";
13
13
  import "../chunk-ROTPP5CU.mjs";
14
14
  import {
15
15
  BlockPicker,
@@ -41,17 +41,22 @@ var resolveUploadUrl = (value) => {
41
41
  var resolveLogoUrl = (settings) => {
42
42
  return resolveUploadUrl(settings.logo) || resolveUploadUrl(settings.adminLogo) || resolveUploadUrl(settings.brandLogo) || null;
43
43
  };
44
+ var resolveLogoOnDarkUrl = (settings) => {
45
+ return resolveUploadUrl(settings.logoOnDark) || resolveUploadUrl(settings.logoDark) || resolveUploadUrl(settings.adminLogoDark) || resolveUploadUrl(settings.adminLogoOnDark) || resolveUploadUrl(settings.brandLogoDark) || null;
46
+ };
44
47
  var cachedBranding = null;
45
- function useSiteBranding(defaultName, defaultLogoUrl) {
48
+ function useSiteBranding(defaultName, defaultLogoUrl, defaultLogoOnDarkUrl) {
46
49
  const [branding, setBranding] = useState(() => {
47
50
  if (cachedBranding) {
48
51
  return {
49
52
  logoUrl: cachedBranding.logoUrl || defaultLogoUrl || null,
53
+ logoOnDarkUrl: cachedBranding.logoOnDarkUrl || defaultLogoOnDarkUrl || null,
50
54
  siteName: cachedBranding.siteName || defaultName || null
51
55
  };
52
56
  }
53
57
  return {
54
58
  logoUrl: defaultLogoUrl || null,
59
+ logoOnDarkUrl: defaultLogoOnDarkUrl || null,
55
60
  siteName: defaultName || null
56
61
  };
57
62
  });
@@ -68,9 +73,11 @@ function useSiteBranding(defaultName, defaultLogoUrl) {
68
73
  if (!record) return;
69
74
  const siteName = pickString(record.siteName);
70
75
  const logoUrl = resolveLogoUrl(record);
71
- cachedBranding = { logoUrl, siteName };
76
+ const logoOnDarkUrl = resolveLogoOnDarkUrl(record);
77
+ cachedBranding = { logoOnDarkUrl, logoUrl, siteName };
72
78
  if (!cancelled) {
73
79
  setBranding({
80
+ logoOnDarkUrl: logoOnDarkUrl || defaultLogoOnDarkUrl || null,
74
81
  logoUrl: logoUrl || defaultLogoUrl || null,
75
82
  siteName: siteName || defaultName || null
76
83
  });
@@ -82,16 +89,20 @@ function useSiteBranding(defaultName, defaultLogoUrl) {
82
89
  return () => {
83
90
  cancelled = true;
84
91
  };
85
- }, [defaultLogoUrl, defaultName]);
92
+ }, [defaultLogoOnDarkUrl, defaultLogoUrl, defaultName]);
86
93
  return branding;
87
94
  }
88
95
 
89
96
  // src/admin/components/Logo.tsx
90
- import { jsx, jsxs } from "react/jsx-runtime";
91
- function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
92
- const branding = useSiteBranding(brandName, logoUrl);
97
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
98
+ function Logo({ brandName = "Orion Studio", logoOnDarkUrl, logoUrl } = {}) {
99
+ const branding = useSiteBranding(brandName, logoUrl, logoOnDarkUrl);
93
100
  const resolvedName = branding.siteName || brandName;
94
101
  const resolvedLogo = branding.logoUrl || logoUrl || null;
102
+ const resolvedLogoOnDark = branding.logoOnDarkUrl || logoOnDarkUrl || resolvedLogo || "";
103
+ const hasDarkLogoVariant = Boolean(
104
+ resolvedLogo && resolvedLogoOnDark.trim().length > 0 && resolvedLogoOnDark !== resolvedLogo
105
+ );
95
106
  return /* @__PURE__ */ jsxs(
96
107
  "div",
97
108
  {
@@ -110,8 +121,6 @@ function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
110
121
  className: "orion-admin-logo-mark",
111
122
  style: {
112
123
  alignItems: "center",
113
- background: "var(--orion-cms-logo-bg, var(--admin-accent, #3b82f6))",
114
- borderRadius: "var(--orion-cms-logo-radius, var(--admin-radius-md, 8px))",
115
124
  display: "flex",
116
125
  flexShrink: 0,
117
126
  height: 32,
@@ -119,14 +128,25 @@ function Logo({ brandName = "Orion Studio", logoUrl } = {}) {
119
128
  overflow: "hidden",
120
129
  width: 32
121
130
  },
122
- children: resolvedLogo ? /* @__PURE__ */ jsx(
123
- "img",
124
- {
125
- alt: `${resolvedName} logo`,
126
- src: resolvedLogo,
127
- style: { height: "100%", objectFit: "cover", width: "100%" }
128
- }
129
- ) : /* @__PURE__ */ jsxs(
131
+ children: resolvedLogo ? /* @__PURE__ */ jsxs(Fragment, { children: [
132
+ /* @__PURE__ */ jsx(
133
+ "img",
134
+ {
135
+ alt: `${resolvedName} logo`,
136
+ className: `orion-admin-logo-image orion-admin-logo-image--default${hasDarkLogoVariant ? "" : " is-only-logo"}`,
137
+ src: resolvedLogo
138
+ }
139
+ ),
140
+ hasDarkLogoVariant ? /* @__PURE__ */ jsx(
141
+ "img",
142
+ {
143
+ alt: "",
144
+ "aria-hidden": "true",
145
+ className: "orion-admin-logo-image orion-admin-logo-image--dark",
146
+ src: resolvedLogoOnDark
147
+ }
148
+ ) : null
149
+ ] }) : /* @__PURE__ */ jsxs(
130
150
  "svg",
131
151
  {
132
152
  fill: "none",
@@ -234,27 +254,13 @@ function AdminLoginIntro({ brandName = "Orion Studio", logoUrl } = {}) {
234
254
  const branding = useSiteBranding(brandName, logoUrl);
235
255
  const resolvedName = branding.siteName || brandName;
236
256
  return /* @__PURE__ */ jsxs3("div", { className: "orion-admin-login-intro", children: [
237
- /* @__PURE__ */ jsx3("span", { className: "orion-admin-login-eyebrow", children: "Studio Access" }),
257
+ /* @__PURE__ */ jsx3("span", { className: "orion-admin-login-eyebrow", children: "Private Admin" }),
238
258
  /* @__PURE__ */ jsxs3("h1", { children: [
239
- "Manage ",
240
259
  resolvedName,
241
- " without losing the site's voice."
260
+ " admin"
242
261
  ] }),
243
- /* @__PURE__ */ jsx3("p", { children: "Sign in to update content, review leads, and keep the public site aligned with the same brand experience your visitors already know." }),
244
- /* @__PURE__ */ jsxs3("div", { className: "orion-admin-login-note-grid", children: [
245
- /* @__PURE__ */ jsxs3("article", { className: "orion-admin-login-note", children: [
246
- /* @__PURE__ */ jsx3("strong", { children: "Branded workspace" }),
247
- /* @__PURE__ */ jsx3("span", { children: "The admin mirrors the live site instead of dropping editors into a generic CMS shell." })
248
- ] }),
249
- /* @__PURE__ */ jsxs3("article", { className: "orion-admin-login-note", children: [
250
- /* @__PURE__ */ jsx3("strong", { children: "One editorial flow" }),
251
- /* @__PURE__ */ jsx3("span", { children: "Pages, globals, media, forms, and analytics stay in one place once you are inside." })
252
- ] }),
253
- /* @__PURE__ */ jsxs3("article", { className: "orion-admin-login-note", children: [
254
- /* @__PURE__ */ jsx3("strong", { children: "Protected entry" }),
255
- /* @__PURE__ */ jsx3("span", { children: "Only authorized administrators and editors can access this workspace." })
256
- ] })
257
- ] })
262
+ /* @__PURE__ */ jsx3("p", { children: "Sign in to update pages, review forms, manage media, and adjust site settings." }),
263
+ /* @__PURE__ */ jsx3("p", { className: "orion-admin-login-caption", children: "For owners and authorized team members." })
258
264
  ] });
259
265
  }
260
266
 
@@ -477,7 +483,7 @@ function useTheme(defaultTheme = "brand-light") {
477
483
  }
478
484
 
479
485
  // src/admin/components/ThemeSwitcher.tsx
480
- import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
486
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
481
487
  var iconSize = 16;
482
488
  function SunIcon() {
483
489
  return /* @__PURE__ */ jsxs5("svg", { width: iconSize, height: iconSize, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", children: [
@@ -617,7 +623,7 @@ function ThemeProvider({
617
623
  } catch {
618
624
  }
619
625
  }, [allowThemePreference, defaultTheme]);
620
- return /* @__PURE__ */ jsx5(Fragment, { children });
626
+ return /* @__PURE__ */ jsx5(Fragment2, { children });
621
627
  }
622
628
 
623
629
  // src/admin/components/HelpTooltip.tsx
@@ -1267,9 +1273,9 @@ function WelcomeHeader({
1267
1273
  }
1268
1274
 
1269
1275
  // src/admin/components/studio/AdminStudioNav.tsx
1270
- import { useMemo } from "react";
1276
+ import { useMemo, useState as useState7 } from "react";
1271
1277
  import { usePathname } from "next/navigation";
1272
- import { Logout, useAuth } from "@payloadcms/ui";
1278
+ import { useAuth } from "@payloadcms/ui";
1273
1279
 
1274
1280
  // src/admin/components/studio/adminPathUtils.ts
1275
1281
  import { useEffect as useEffect6, useState as useState6 } from "react";
@@ -1347,7 +1353,7 @@ var useAdminBasePath = (fallback = DEFAULT_ADMIN_BASE_PATH) => {
1347
1353
  };
1348
1354
 
1349
1355
  // src/shared/studioSections.ts
1350
- var studioRoles = /* @__PURE__ */ new Set(["admin", "editor", "client"]);
1356
+ var studioRoles = /* @__PURE__ */ new Set(["admin", "developer", "editor", "client"]);
1351
1357
  var studioIcons = new Set(adminNavIcons);
1352
1358
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
1353
1359
  var isAbsoluteExternalURL2 = (value) => /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(value) || value.startsWith("//");
@@ -1545,7 +1551,7 @@ var buildStudioNavItems = (props, adminBasePath) => {
1545
1551
  icon: "tools",
1546
1552
  label: "Admin Tools",
1547
1553
  matchPrefixes: [toolsPath, resolveAdminPath(adminBasePath, "/collections/users")],
1548
- roles: ["admin"]
1554
+ roles: ["admin", "developer"]
1549
1555
  };
1550
1556
  const extensionItems = sections.map((section) => ({
1551
1557
  href: resolveAdminPath(adminBasePath, section.href),
@@ -1582,7 +1588,7 @@ var isStudioShellRoute = (pathname, props, adminBasePath) => {
1582
1588
  };
1583
1589
 
1584
1590
  // src/admin/components/studio/AdminStudioNav.tsx
1585
- import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1591
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1586
1592
  var iconSize2 = 18;
1587
1593
  function NavIcon({ sectionID }) {
1588
1594
  const props = {
@@ -1642,8 +1648,26 @@ function NavIcon({ sectionID }) {
1642
1648
  return null;
1643
1649
  }
1644
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
+ }
1645
1668
  function AdminStudioNav(props) {
1646
1669
  const { user } = useAuth();
1670
+ const [loggingOut, setLoggingOut] = useState7(false);
1647
1671
  const brandName = getPropString(props, "brandName", "Orion Studio");
1648
1672
  const logoUrl = getPropString(props, "logoUrl", "");
1649
1673
  const compact = getPropBoolean(props, "compact", false);
@@ -1654,6 +1678,18 @@ function AdminStudioNav(props) {
1654
1678
  const dashboardPath = adminBasePath;
1655
1679
  const userRole = readUserRole(user);
1656
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
+ };
1657
1693
  if (isStudioShellRoute(pathname, props, adminBasePath)) {
1658
1694
  return null;
1659
1695
  }
@@ -1740,11 +1776,42 @@ function AdminStudioNav(props) {
1740
1776
  textAlign: compact ? "center" : "left"
1741
1777
  },
1742
1778
  children: [
1743
- !compact ? /* @__PURE__ */ jsxs11(Fragment2, { children: [
1779
+ !compact ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
1744
1780
  /* @__PURE__ */ jsx12("div", { style: { color: "var(--theme-elevation-700)", fontSize: "0.85rem" }, children: "Signed in as" }),
1745
1781
  /* @__PURE__ */ jsx12("div", { style: { fontWeight: 800, marginBottom: "0.55rem" }, children: typeof user?.email === "string" ? user.email : "User" })
1746
1782
  ] }) : null,
1747
- /* @__PURE__ */ jsx12(Logout, {})
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
+ )
1748
1815
  ]
1749
1816
  }
1750
1817
  )
@@ -1834,13 +1901,13 @@ function AdminPage({ title, description, breadcrumbs, actions, children }) {
1834
1901
  }
1835
1902
 
1836
1903
  // src/admin/components/studio/AdminStudioDashboardClient.tsx
1837
- import { startTransition, useEffect as useEffect7, useMemo as useMemo3, useState as useState7 } from "react";
1904
+ import { startTransition, useEffect as useEffect7, useMemo as useMemo3, useState as useState8 } from "react";
1838
1905
  import Link from "next/link";
1839
1906
  import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1840
1907
  var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1e3;
1841
- var isRole = (value) => value === "admin" || value === "editor" || value === "client";
1842
- var canReviewForms = (role) => role === "admin" || role === "editor";
1843
- 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";
1844
1911
  var canAccess = (role, roles) => {
1845
1912
  if (!roles || roles.length === 0) {
1846
1913
  return true;
@@ -2056,7 +2123,7 @@ function AdminStudioDashboardClient({
2056
2123
  children
2057
2124
  }) {
2058
2125
  const role = isRole(userRole) ? userRole : void 0;
2059
- const [state, setState] = useState7(
2126
+ const [state, setState] = useState8(
2060
2127
  () => formsEnabled && canReviewForms(role) ? {
2061
2128
  forms: { status: "loading" },
2062
2129
  media: { status: "loading" },
@@ -2316,7 +2383,7 @@ function AdminStudioDashboardClient({
2316
2383
  label: "Manage Media",
2317
2384
  tone: "ghost"
2318
2385
  });
2319
- if (role === "admin") {
2386
+ if (role === "admin" || role === "developer") {
2320
2387
  actions.push({
2321
2388
  description: "Manage users, roles, and fallback tools.",
2322
2389
  href: toolsPath,
@@ -2595,7 +2662,7 @@ var buildSectionLinks = (adminBasePath, sections, formsEnabled, globalsBasePath)
2595
2662
  href: resolveAdminPath2(adminBasePath, "/tools"),
2596
2663
  id: "admin-tools",
2597
2664
  label: "Admin Tools",
2598
- roles: ["admin"]
2665
+ roles: ["admin", "developer"]
2599
2666
  }
2600
2667
  ];
2601
2668
  const seen = /* @__PURE__ */ new Set();
@@ -2661,15 +2728,16 @@ function AdminStudioDashboard(rawProps) {
2661
2728
  }
2662
2729
 
2663
2730
  // src/admin/components/studio/AdminStudioPagesListView.tsx
2664
- import { useEffect as useEffect8, useMemo as useMemo4, useState as useState8 } from "react";
2731
+ import { useEffect as useEffect9, useMemo as useMemo5, useState as useState11 } from "react";
2665
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";
2666
2738
  import { useAuth as useAuth3 } from "@payloadcms/ui";
2667
2739
  import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2668
- var isAdmin = (user) => {
2669
- if (!user || typeof user !== "object") return false;
2670
- const role = user.role;
2671
- return typeof role === "string" && role === "admin";
2672
- };
2740
+ var pageTemplates = ["standard", "landing", "services", "contact"];
2673
2741
  var getPropString3 = (props, key, fallback) => {
2674
2742
  if (!props || typeof props !== "object") return fallback;
2675
2743
  const direct = props[key];
@@ -2681,101 +2749,115 @@ var getPropString3 = (props, key, fallback) => {
2681
2749
  }
2682
2750
  return fallback;
2683
2751
  };
2684
- function AdminStudioPagesListView(props) {
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) {
2685
2759
  const { user } = useAuth3();
2686
- const pagesCollectionSlug = getPropString3(props, "pagesCollectionSlug", "pages");
2687
2760
  const adminBasePath = useAdminBasePath();
2688
- const newPagePath = resolveAdminPath(adminBasePath, "/pages/new");
2689
- const [loading, setLoading] = useState8(true);
2690
- const [error, setError] = useState8(null);
2691
- const [docs, setDocs] = useState8([]);
2692
- const apiURL = useMemo4(() => {
2693
- const params = new URLSearchParams({
2694
- depth: "0",
2695
- limit: "100",
2696
- sort: "-updatedAt",
2697
- draft: "true"
2698
- });
2699
- return `/api/${pagesCollectionSlug}?${params.toString()}`;
2700
- }, [pagesCollectionSlug]);
2701
- useEffect8(() => {
2702
- let cancelled = false;
2703
- const run = async () => {
2704
- setLoading(true);
2705
- setError(null);
2706
- try {
2707
- const res = await fetch(apiURL, { credentials: "include" });
2708
- if (!res.ok) {
2709
- const body = await res.text();
2710
- throw new Error(body || "Failed to fetch pages");
2711
- }
2712
- const data = await res.json();
2713
- if (!cancelled) {
2714
- setDocs(Array.isArray(data.docs) ? data.docs : []);
2715
- }
2716
- } catch (err) {
2717
- if (!cancelled) {
2718
- setError(err instanceof Error ? err.message : "Failed to fetch pages");
2719
- }
2720
- } finally {
2721
- if (!cancelled) {
2722
- setLoading(false);
2723
- }
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
+ ] })
2724
2779
  }
2725
- };
2726
- void run();
2727
- return () => {
2728
- cancelled = true;
2729
- };
2730
- }, [apiURL]);
2731
- return /* @__PURE__ */ jsx18(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs15(
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(
2732
2823
  AdminPage,
2733
2824
  {
2734
- actions: isAdmin(user) ? /* @__PURE__ */ jsx18(Link2, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
2735
2825
  breadcrumbs: [
2736
2826
  { label: "Dashboard", href: adminBasePath },
2737
- { label: "Pages" }
2827
+ { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
2828
+ { label: "New Page" }
2738
2829
  ],
2739
- description: "Open a page to edit it in the inline custom builder.",
2740
- title: "Pages",
2741
- children: [
2742
- 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: [
2743
2833
  error ? /* @__PURE__ */ jsx18("div", { className: "orion-admin-error", children: error }) : null,
2744
- /* @__PURE__ */ jsxs15("div", { className: "orion-admin-list", children: [
2745
- !loading && !error && docs.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: "orion-admin-card", children: [
2746
- /* @__PURE__ */ jsx18("strong", { children: "No pages yet" }),
2747
- /* @__PURE__ */ jsx18("span", { children: "Create the first page to start building content." })
2748
- ] }) : null,
2749
- docs.map((doc) => {
2750
- const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
2751
- if (!id) return null;
2752
- const title = typeof doc.title === "string" ? doc.title : "Untitled Page";
2753
- const status = typeof doc._status === "string" ? doc._status : "draft";
2754
- return /* @__PURE__ */ jsxs15(Link2, { className: "orion-admin-list-item", href: resolveAdminPath(adminBasePath, `/pages/${id}`), children: [
2755
- /* @__PURE__ */ jsx18("div", { children: /* @__PURE__ */ jsx18("strong", { children: title }) }),
2756
- /* @__PURE__ */ jsx18("span", { className: "orion-admin-pill", children: status })
2757
- ] }, id);
2758
- })
2759
- ] })
2760
- ]
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
+ ] })
2761
2853
  }
2762
2854
  ) });
2763
2855
  }
2764
2856
 
2765
2857
  // src/admin/components/studio/AdminStudioPageEditView.tsx
2766
- import { useEffect as useEffect9, useMemo as useMemo5, useRef as useRef3, useState as useState9 } from "react";
2767
- import { SetStepNav, toast, useAuth as useAuth4 } from "@payloadcms/ui";
2768
- import { Fragment as Fragment3, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2769
- var isAdmin2 = (user) => {
2770
- if (!user || typeof user !== "object") return false;
2771
- const role = user.role;
2772
- return typeof role === "string" && role === "admin";
2773
- };
2774
- var isEditor = (user) => {
2775
- if (!user || typeof user !== "object") return false;
2776
- const role = user.role;
2777
- return typeof role === "string" && role === "editor";
2778
- };
2858
+ import { useEffect as useEffect8, useMemo as useMemo4, useRef as useRef3, useState as useState10 } from "react";
2859
+ import { SetStepNav } from "@payloadcms/ui";
2860
+ import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2779
2861
  var getPropString4 = (props, key, fallback) => {
2780
2862
  if (!props || typeof props !== "object") return fallback;
2781
2863
  const direct = props[key];
@@ -2803,20 +2885,14 @@ var getPageIDFromPathname = (pathname) => {
2803
2885
  return pagePart ? decodeURIComponent(pagePart) : null;
2804
2886
  };
2805
2887
  function AdminStudioPageEditView(props) {
2806
- const { user } = useAuth4();
2807
2888
  const adminBasePath = useAdminBasePath();
2808
2889
  const iframeRef = useRef3(null);
2809
- const [saving, setSaving] = useState9(null);
2810
- const [dirty, setDirty] = useState9(false);
2811
- const [hasUnpublishedChanges, setHasUnpublishedChanges] = useState9(false);
2812
- const [canUndo, setCanUndo] = useState9(false);
2813
- const [canRedo, setCanRedo] = useState9(false);
2814
2890
  const builderBasePath = getPropString4(props, "builderBasePath", "/builder");
2815
2891
  const pagesPath = resolveAdminPath(adminBasePath, "/pages");
2816
- const pageIDFromParams = useMemo5(() => getParam(props.params, "id"), [props.params]);
2817
- const [pageID, setPageID] = useState9(pageIDFromParams);
2818
- const [didResolvePathFallback, setDidResolvePathFallback] = useState9(false);
2819
- useEffect9(() => {
2892
+ const pageIDFromParams = useMemo4(() => getParam(props.params, "id"), [props.params]);
2893
+ const [pageID, setPageID] = useState10(pageIDFromParams);
2894
+ const [didResolvePathFallback, setDidResolvePathFallback] = useState10(false);
2895
+ useEffect8(() => {
2820
2896
  if (pageIDFromParams) {
2821
2897
  setPageID(pageIDFromParams);
2822
2898
  setDidResolvePathFallback(true);
@@ -2827,98 +2903,8 @@ function AdminStudioPageEditView(props) {
2827
2903
  }
2828
2904
  setDidResolvePathFallback(true);
2829
2905
  }, [pageIDFromParams]);
2830
- const canPublish = isAdmin2(user) || isEditor(user);
2831
- const refreshUnpublishedState = async (id) => {
2832
- try {
2833
- const response = await fetch(
2834
- `/api/pages/versions?depth=0&limit=25&sort=-updatedAt&where[parent][equals]=${encodeURIComponent(id)}`,
2835
- {
2836
- credentials: "include"
2837
- }
2838
- );
2839
- if (!response.ok) {
2840
- return;
2841
- }
2842
- const payload = await response.json();
2843
- const docs = Array.isArray(payload.docs) ? payload.docs : [];
2844
- let latestDraft = 0;
2845
- let latestPublished = 0;
2846
- docs.forEach((doc) => {
2847
- const status = doc.version?._status;
2848
- const millis = typeof doc.updatedAt === "string" ? Date.parse(doc.updatedAt) : Number.NaN;
2849
- if (!Number.isFinite(millis)) {
2850
- return;
2851
- }
2852
- if (status === "draft") {
2853
- latestDraft = Math.max(latestDraft, millis);
2854
- }
2855
- if (status === "published") {
2856
- latestPublished = Math.max(latestPublished, millis);
2857
- }
2858
- });
2859
- setHasUnpublishedChanges(latestDraft > 0 && latestDraft >= latestPublished);
2860
- } catch {
2861
- }
2862
- };
2863
- useEffect9(() => {
2864
- if (!pageID) {
2865
- return;
2866
- }
2867
- void refreshUnpublishedState(pageID);
2868
- }, [pageID]);
2869
- const requestSave = (status) => {
2870
- const iframe = iframeRef.current;
2871
- if (!iframe?.contentWindow) {
2872
- toast.error("Editor is not ready yet. Please try again.");
2873
- return;
2874
- }
2875
- setSaving(status);
2876
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "save", status }, "*");
2877
- };
2878
- const requestHistoryAction = (type) => {
2879
- const iframe = iframeRef.current;
2880
- if (!iframe?.contentWindow) {
2881
- toast.error("Editor is not ready yet. Please try again.");
2882
- return;
2883
- }
2884
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type }, "*");
2885
- };
2886
- useEffect9(() => {
2887
- const onMessage = (event) => {
2888
- const data = event.data;
2889
- if (!data || data.source !== "payload-visual-builder-child" || typeof data.type !== "string") {
2890
- return;
2891
- }
2892
- if (data.type === "dirty-state") {
2893
- setDirty(Boolean(data.dirty));
2894
- return;
2895
- }
2896
- if (data.type === "history-state") {
2897
- setCanUndo(Boolean(data.canUndo));
2898
- setCanRedo(Boolean(data.canRedo));
2899
- return;
2900
- }
2901
- if (data.type === "save-result") {
2902
- setSaving(null);
2903
- if (data.ok) {
2904
- if (data.status === "draft") {
2905
- setHasUnpublishedChanges(true);
2906
- } else if (data.status === "published") {
2907
- setHasUnpublishedChanges(false);
2908
- } else if (pageID) {
2909
- void refreshUnpublishedState(pageID);
2910
- }
2911
- toast.success(typeof data.message === "string" ? data.message : "Saved.");
2912
- } else {
2913
- toast.error(typeof data.message === "string" ? data.message : "Save failed.");
2914
- }
2915
- }
2916
- };
2917
- window.addEventListener("message", onMessage);
2918
- return () => window.removeEventListener("message", onMessage);
2919
- }, []);
2920
2906
  if (!pageID && !didResolvePathFallback) {
2921
- return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment3, { children: [
2907
+ return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment4, { children: [
2922
2908
  /* @__PURE__ */ jsx19(
2923
2909
  SetStepNav,
2924
2910
  {
@@ -2933,7 +2919,7 @@ function AdminStudioPageEditView(props) {
2933
2919
  ] }) });
2934
2920
  }
2935
2921
  if (!pageID) {
2936
- return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment3, { children: [
2922
+ return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment4, { children: [
2937
2923
  /* @__PURE__ */ jsx19(
2938
2924
  SetStepNav,
2939
2925
  {
@@ -2947,7 +2933,7 @@ function AdminStudioPageEditView(props) {
2947
2933
  /* @__PURE__ */ jsx19("p", { style: { color: "var(--theme-elevation-600)" }, children: "Missing page ID." })
2948
2934
  ] }) });
2949
2935
  }
2950
- return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment3, { children: [
2936
+ return /* @__PURE__ */ jsx19(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs16(Fragment4, { children: [
2951
2937
  /* @__PURE__ */ jsx19(
2952
2938
  SetStepNav,
2953
2939
  {
@@ -2957,155 +2943,25 @@ function AdminStudioPageEditView(props) {
2957
2943
  ]
2958
2944
  }
2959
2945
  ),
2960
- /* @__PURE__ */ jsxs16("div", { style: { display: "grid", gridTemplateRows: "auto 1fr", height: "calc(100vh - 120px)" }, children: [
2961
- /* @__PURE__ */ jsxs16(
2962
- "div",
2963
- {
2964
- style: {
2965
- alignItems: "center",
2966
- background: "var(--theme-elevation-0)",
2967
- borderBottom: "1px solid var(--theme-elevation-150)",
2968
- display: "flex",
2969
- gap: "0.6rem",
2970
- justifyContent: "space-between",
2971
- padding: "0.65rem 0.9rem",
2972
- position: "sticky",
2973
- top: 0,
2974
- zIndex: 20
2975
- },
2976
- children: [
2977
- /* @__PURE__ */ jsxs16("div", { style: { minWidth: 0 }, children: [
2978
- /* @__PURE__ */ jsx19("div", { style: { fontWeight: 900 }, children: "Page Editor" }),
2979
- /* @__PURE__ */ jsxs16(
2980
- "div",
2981
- {
2982
- style: {
2983
- color: "var(--theme-elevation-600)",
2984
- fontSize: "0.85rem",
2985
- overflow: "hidden",
2986
- textOverflow: "ellipsis"
2987
- },
2988
- children: [
2989
- "Editing: ",
2990
- pageID
2991
- ]
2992
- }
2993
- )
2994
- ] }),
2995
- /* @__PURE__ */ jsxs16("div", { style: { alignItems: "center", display: "flex", gap: "0.5rem" }, children: [
2996
- /* @__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" }),
2997
- /* @__PURE__ */ jsx19(
2998
- "div",
2999
- {
3000
- style: {
3001
- background: hasUnpublishedChanges ? "#fff3cd" : "var(--theme-success-50)",
3002
- border: `1px solid ${hasUnpublishedChanges ? "#f0c36d" : "var(--theme-success-300)"}`,
3003
- borderRadius: 999,
3004
- color: hasUnpublishedChanges ? "#6a4a00" : "var(--theme-success-700)",
3005
- fontSize: "0.75rem",
3006
- fontWeight: 800,
3007
- padding: "0.2rem 0.55rem",
3008
- whiteSpace: "nowrap"
3009
- },
3010
- title: hasUnpublishedChanges ? "There are saved draft changes not yet published." : "The live page matches the latest published content.",
3011
- children: hasUnpublishedChanges ? "Unpublished draft changes" : "Live is up to date"
3012
- }
3013
- ),
3014
- /* @__PURE__ */ jsx19(
3015
- "button",
3016
- {
3017
- disabled: !canUndo,
3018
- onClick: () => requestHistoryAction("undo"),
3019
- style: {
3020
- border: "1px solid var(--theme-elevation-300)",
3021
- borderRadius: 12,
3022
- cursor: canUndo ? "pointer" : "not-allowed",
3023
- fontWeight: 800,
3024
- padding: "0.5rem 0.65rem"
3025
- },
3026
- type: "button",
3027
- children: "Undo"
3028
- }
3029
- ),
3030
- /* @__PURE__ */ jsx19(
3031
- "button",
3032
- {
3033
- disabled: !canRedo,
3034
- onClick: () => requestHistoryAction("redo"),
3035
- style: {
3036
- border: "1px solid var(--theme-elevation-300)",
3037
- borderRadius: 12,
3038
- cursor: canRedo ? "pointer" : "not-allowed",
3039
- fontWeight: 800,
3040
- padding: "0.5rem 0.65rem"
3041
- },
3042
- type: "button",
3043
- children: "Redo"
3044
- }
3045
- ),
3046
- /* @__PURE__ */ jsx19(
3047
- "button",
3048
- {
3049
- disabled: saving !== null,
3050
- onClick: () => requestSave("draft"),
3051
- style: {
3052
- border: "1px solid var(--theme-elevation-300)",
3053
- borderRadius: 12,
3054
- cursor: saving ? "not-allowed" : "pointer",
3055
- fontWeight: 800,
3056
- padding: "0.5rem 0.75rem"
3057
- },
3058
- type: "button",
3059
- children: saving === "draft" ? "Saving\u2026" : "Save Draft"
3060
- }
3061
- ),
3062
- /* @__PURE__ */ jsx19(
3063
- "button",
3064
- {
3065
- disabled: !canPublish || saving !== null,
3066
- onClick: () => requestSave("published"),
3067
- style: {
3068
- background: canPublish ? "var(--theme-success-700)" : "var(--theme-elevation-300)",
3069
- border: "none",
3070
- borderRadius: 12,
3071
- color: canPublish ? "var(--theme-elevation-0)" : "var(--theme-elevation-700)",
3072
- cursor: !canPublish || saving ? "not-allowed" : "pointer",
3073
- fontWeight: 900,
3074
- padding: "0.5rem 0.75rem"
3075
- },
3076
- type: "button",
3077
- title: !canPublish ? "You do not have publish permissions." : void 0,
3078
- children: saving === "published" ? "Publishing\u2026" : "Publish"
3079
- }
3080
- )
3081
- ] })
3082
- ]
3083
- }
3084
- ),
3085
- /* @__PURE__ */ jsx19(
3086
- "iframe",
3087
- {
3088
- ref: iframeRef,
3089
- src: `${builderBasePath.replace(/\/$/, "")}/${pageID}`,
3090
- style: { border: "none", height: "100%", width: "100%" },
3091
- title: "Page Builder",
3092
- onLoad: () => {
3093
- const iframe = iframeRef.current;
3094
- if (!iframe?.contentWindow) return;
3095
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "dirty-check-request" }, "*");
3096
- iframe.contentWindow.postMessage({ source: "payload-visual-builder-parent", type: "history-check-request" }, "*");
3097
- }
3098
- }
3099
- )
3100
- ] })
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
+ ) })
3101
2955
  ] }) });
3102
2956
  }
3103
2957
 
3104
- // src/admin/components/studio/AdminStudioNewPageView.tsx
3105
- import { useState as useState10 } from "react";
3106
- import { useAuth as useAuth5 } from "@payloadcms/ui";
2958
+ // src/admin/components/studio/AdminStudioPagesListView.tsx
3107
2959
  import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
3108
- var pageTemplates = ["standard", "landing", "services", "contact"];
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
+ };
3109
2965
  var getPropString5 = (props, key, fallback) => {
3110
2966
  if (!props || typeof props !== "object") return fallback;
3111
2967
  const direct = props[key];
@@ -3117,107 +2973,98 @@ var getPropString5 = (props, key, fallback) => {
3117
2973
  }
3118
2974
  return fallback;
3119
2975
  };
3120
- var canManagePages = (user) => {
3121
- if (!user || typeof user !== "object") return false;
3122
- const role = user.role;
3123
- return role === "admin" || role === "editor";
3124
- };
3125
- var slugify = (value) => value.toLowerCase().trim().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-");
3126
- function AdminStudioNewPageView(props) {
3127
- const { user } = useAuth5();
2976
+ function AdminStudioPagesListView(props) {
3128
2977
  const adminBasePath = useAdminBasePath();
3129
- const pagesCollectionSlug = getPropString5(props, "pagesCollectionSlug", "pages");
3130
- const [submitting, setSubmitting] = useState10(false);
3131
- const [error, setError] = useState10(null);
3132
- if (!canManagePages(user)) {
3133
- return /* @__PURE__ */ jsx20(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx20(
3134
- AdminPage,
3135
- {
3136
- breadcrumbs: [
3137
- { label: "Dashboard", href: adminBasePath },
3138
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
3139
- { label: "New Page" }
3140
- ],
3141
- description: "You do not have access to create pages.",
3142
- title: "New Page",
3143
- children: /* @__PURE__ */ jsxs17("div", { className: "orion-admin-card", children: [
3144
- /* @__PURE__ */ jsx20("strong", { children: "Access denied" }),
3145
- /* @__PURE__ */ jsx20("span", { children: "This section is restricted to administrator and editor accounts." })
3146
- ] })
3147
- }
3148
- ) });
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 });
3149
2983
  }
3150
- const createPage = async (event) => {
3151
- event.preventDefault();
3152
- setSubmitting(true);
3153
- setError(null);
3154
- try {
3155
- const formData = new FormData(event.currentTarget);
3156
- const titleValue = String(formData.get("title") || "").trim();
3157
- const slugValue = String(formData.get("slug") || "").trim();
3158
- const templateValue = String(formData.get("template") || "standard").trim();
3159
- const template = pageTemplates.includes(templateValue) ? templateValue : "standard";
3160
- const title = titleValue || "Untitled Page";
3161
- const slug = slugValue || slugify(title) || "untitled-page";
3162
- const response = await fetch(`/api/${pagesCollectionSlug}`, {
3163
- body: JSON.stringify({
3164
- _status: "draft",
3165
- slug,
3166
- template,
3167
- title
3168
- }),
3169
- credentials: "include",
3170
- headers: {
3171
- "Content-Type": "application/json"
3172
- },
3173
- method: "POST"
3174
- });
3175
- if (!response.ok) {
3176
- throw new Error(`Failed to create page (${response.status}).`);
3177
- }
3178
- const payload = await response.json();
3179
- const id = typeof payload.id === "string" || typeof payload.id === "number" ? String(payload.id) : "";
3180
- if (!id) {
3181
- throw new Error("Page created but no document ID was returned.");
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
+ }
3182
3031
  }
3183
- window.location.assign(resolveAdminPath(adminBasePath, `/pages/${id}`));
3184
- } catch (createError) {
3185
- setError(createError instanceof Error ? createError.message : "Failed to create page.");
3186
- } finally {
3187
- setSubmitting(false);
3188
- }
3189
- };
3190
- 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(
3191
3039
  AdminPage,
3192
3040
  {
3041
+ actions: hasAdminAccess(user) ? /* @__PURE__ */ jsx20(Link2, { className: "orion-admin-action-button", href: newPagePath, children: "New Page" }) : null,
3193
3042
  breadcrumbs: [
3194
3043
  { label: "Dashboard", href: adminBasePath },
3195
- { label: "Pages", href: resolveAdminPath(adminBasePath, "/pages") },
3196
- { label: "New Page" }
3044
+ { label: "Pages" }
3197
3045
  ],
3198
- description: "Create a new page and open it in the custom editor.",
3199
- title: "New Page",
3200
- children: /* @__PURE__ */ jsxs17("form", { className: "orion-admin-form", onSubmit: createPage, 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,
3201
3050
  error ? /* @__PURE__ */ jsx20("div", { className: "orion-admin-error", children: error }) : null,
3202
- /* @__PURE__ */ jsxs17("label", { children: [
3203
- "Title",
3204
- /* @__PURE__ */ jsx20("input", { name: "title", placeholder: "Services", required: true, type: "text" })
3205
- ] }),
3206
- /* @__PURE__ */ jsxs17("label", { children: [
3207
- "Slug",
3208
- /* @__PURE__ */ jsx20("input", { name: "slug", placeholder: "services", type: "text" })
3209
- ] }),
3210
- /* @__PURE__ */ jsxs17("label", { children: [
3211
- "Template",
3212
- /* @__PURE__ */ jsxs17("select", { defaultValue: "standard", name: "template", children: [
3213
- /* @__PURE__ */ jsx20("option", { value: "standard", children: "Standard" }),
3214
- /* @__PURE__ */ jsx20("option", { value: "landing", children: "Landing" }),
3215
- /* @__PURE__ */ jsx20("option", { value: "contact", children: "Contact" }),
3216
- /* @__PURE__ */ jsx20("option", { value: "services", children: "Services" })
3217
- ] })
3218
- ] }),
3219
- /* @__PURE__ */ jsx20("button", { disabled: submitting, type: "submit", children: submitting ? "Creating..." : "Create Page" })
3220
- ] })
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
+ ]
3221
3068
  }
3222
3069
  ) });
3223
3070
  }
@@ -3270,7 +3117,7 @@ function AdminStudioGlobalsView(props) {
3270
3117
  }
3271
3118
 
3272
3119
  // src/admin/components/studio/AdminStudioSiteSettingsGlobalView.tsx
3273
- import { useEffect as useEffect10, useMemo as useMemo6, useState as useState11 } from "react";
3120
+ import { useEffect as useEffect10, useMemo as useMemo6, useState as useState12 } from "react";
3274
3121
  import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3275
3122
  var getPropString6 = (props, key, fallback) => {
3276
3123
  if (!props || typeof props !== "object") return fallback;
@@ -3356,12 +3203,12 @@ function AdminStudioSiteSettingsGlobalView(props) {
3356
3203
  const mediaCollectionSlug = getPropString6(props, "mediaCollectionSlug", "media");
3357
3204
  const adminBasePath = useAdminBasePath();
3358
3205
  const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
3359
- const [loading, setLoading] = useState11(true);
3360
- const [saving, setSaving] = useState11(false);
3361
- const [error, setError] = useState11(null);
3362
- const [savedMessage, setSavedMessage] = useState11(null);
3363
- const [globalData, setGlobalData] = useState11({});
3364
- const [mediaOptions, setMediaOptions] = useState11([]);
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([]);
3365
3212
  useEffect10(() => {
3366
3213
  let cancelled = false;
3367
3214
  const run = async () => {
@@ -3646,7 +3493,7 @@ function AdminStudioSiteSettingsGlobalView(props) {
3646
3493
  }
3647
3494
 
3648
3495
  // src/admin/components/studio/AdminStudioSocialMediaGlobalView.tsx
3649
- import { useEffect as useEffect11, useMemo as useMemo7, useState as useState12 } from "react";
3496
+ import { useEffect as useEffect11, useMemo as useMemo7, useState as useState13 } from "react";
3650
3497
 
3651
3498
  // src/shared/socialMedia.ts
3652
3499
  var SOCIAL_MEDIA_PLATFORM_LABELS = {
@@ -3783,11 +3630,11 @@ function AdminStudioSocialMediaGlobalView(props) {
3783
3630
  const globalsBasePath = getPropString7(props, "globalsBasePath", "/globals");
3784
3631
  const adminBasePath = useAdminBasePath();
3785
3632
  const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
3786
- const [loading, setLoading] = useState12(true);
3787
- const [saving, setSaving] = useState12(false);
3788
- const [error, setError] = useState12(null);
3789
- const [savedMessage, setSavedMessage] = useState12(null);
3790
- const [globalData, setGlobalData] = useState12({});
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({});
3791
3638
  useEffect11(() => {
3792
3639
  let cancelled = false;
3793
3640
  const run = async () => {
@@ -3927,7 +3774,7 @@ function AdminStudioSocialMediaGlobalView(props) {
3927
3774
  }
3928
3775
 
3929
3776
  // src/admin/components/studio/AdminStudioHeaderGlobalView.tsx
3930
- import { useEffect as useEffect12, useMemo as useMemo8, useState as useState13 } from "react";
3777
+ import { useEffect as useEffect12, useMemo as useMemo8, useState as useState14 } from "react";
3931
3778
  import { SetStepNav as SetStepNav2 } from "@payloadcms/ui";
3932
3779
 
3933
3780
  // src/nextjs/utilities/socialMedia.ts
@@ -4023,15 +3870,15 @@ function AdminStudioHeaderGlobalView(props) {
4023
3870
  const adminBasePath = useAdminBasePath();
4024
3871
  const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
4025
3872
  const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
4026
- const [loading, setLoading] = useState13(true);
4027
- const [saving, setSaving] = useState13(false);
4028
- const [error, setError] = useState13(null);
4029
- const [savedMessage, setSavedMessage] = useState13(null);
4030
- const [initialItems, setInitialItems] = useState13([]);
4031
- const [liveItems, setLiveItems] = useState13([]);
4032
- const [pages, setPages] = useState13([]);
4033
- const [siteSettings, setSiteSettings] = useState13({});
4034
- const [socialMedia, setSocialMedia] = useState13({});
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({});
4035
3882
  useEffect12(() => {
4036
3883
  let cancelled = false;
4037
3884
  const run = async () => {
@@ -4198,7 +4045,7 @@ function AdminStudioHeaderGlobalView(props) {
4198
4045
  }
4199
4046
 
4200
4047
  // src/admin/components/studio/AdminStudioFooterGlobalView.tsx
4201
- import { useEffect as useEffect13, useMemo as useMemo9, useState as useState14 } from "react";
4048
+ import { useEffect as useEffect13, useMemo as useMemo9, useState as useState15 } from "react";
4202
4049
  import { SetStepNav as SetStepNav3 } from "@payloadcms/ui";
4203
4050
  import { jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
4204
4051
  var getPropString9 = (props, key, fallback) => {
@@ -4306,17 +4153,17 @@ function AdminStudioFooterGlobalView(props) {
4306
4153
  const adminBasePath = useAdminBasePath();
4307
4154
  const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
4308
4155
  const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
4309
- const [loading, setLoading] = useState14(true);
4310
- const [saving, setSaving] = useState14(false);
4311
- const [error, setError] = useState14(null);
4312
- const [savedMessage, setSavedMessage] = useState14(null);
4313
- const [doc, setDoc] = useState14({
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({
4314
4161
  contactEmail: "",
4315
4162
  contactPhone: "",
4316
4163
  copyright: ""
4317
4164
  });
4318
- const [siteSettings, setSiteSettings] = useState14({});
4319
- const [socialMedia, setSocialMedia] = useState14({});
4165
+ const [siteSettings, setSiteSettings] = useState15({});
4166
+ const [socialMedia, setSocialMedia] = useState15({});
4320
4167
  useEffect13(() => {
4321
4168
  let cancelled = false;
4322
4169
  const run = async () => {
@@ -4573,7 +4420,7 @@ function AdminStudioFooterGlobalView(props) {
4573
4420
  }
4574
4421
 
4575
4422
  // src/admin/components/studio/AdminStudioContactFormView.tsx
4576
- import { useEffect as useEffect14, useMemo as useMemo10, useState as useState15 } from "react";
4423
+ import { useEffect as useEffect14, useMemo as useMemo10, useState as useState16 } from "react";
4577
4424
  import { SetStepNav as SetStepNav4 } from "@payloadcms/ui";
4578
4425
  import { jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
4579
4426
  var defaultDoc = {
@@ -4664,11 +4511,11 @@ function AdminStudioContactFormView(props) {
4664
4511
  const adminBasePath = useAdminBasePath();
4665
4512
  const resolvedGlobalsBasePath = resolveAdminPath(adminBasePath, globalsBasePath);
4666
4513
  const rawGlobalPath = resolveAdminPath(adminBasePath, `/globals/${globalSlug}`);
4667
- const [doc, setDoc] = useState15(defaultDoc);
4668
- const [error, setError] = useState15(null);
4669
- const [isLoading, setIsLoading] = useState15(true);
4670
- const [isSaving, setIsSaving] = useState15(false);
4671
- const [savedMessage, setSavedMessage] = useState15(null);
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);
4672
4519
  useEffect14(() => {
4673
4520
  let mounted = true;
4674
4521
  const load = async () => {
@@ -4899,7 +4746,7 @@ function AdminStudioContactFormView(props) {
4899
4746
  }
4900
4747
 
4901
4748
  // src/admin/components/studio/AdminStudioMediaView.tsx
4902
- import { useEffect as useEffect15, useMemo as useMemo11, useState as useState16 } from "react";
4749
+ import { useEffect as useEffect15, useMemo as useMemo11, useState as useState17 } from "react";
4903
4750
  import { jsx as jsx27, jsxs as jsxs24 } from "react/jsx-runtime";
4904
4751
  var MEDIA_LIBRARY_SYNC_EVENT = "orion-media-library-updated";
4905
4752
  var getPropString11 = (props, key, fallback) => {
@@ -4916,9 +4763,9 @@ var getPropString11 = (props, key, fallback) => {
4916
4763
  function AdminStudioMediaView(props) {
4917
4764
  const mediaCollectionSlug = getPropString11(props, "mediaCollectionSlug", "media");
4918
4765
  const adminBasePath = useAdminBasePath();
4919
- const [docs, setDocs] = useState16([]);
4920
- const [loading, setLoading] = useState16(true);
4921
- const [error, setError] = useState16(null);
4766
+ const [docs, setDocs] = useState17([]);
4767
+ const [loading, setLoading] = useState17(true);
4768
+ const [error, setError] = useState17(null);
4922
4769
  const apiURL = useMemo11(() => {
4923
4770
  const params = new URLSearchParams({
4924
4771
  depth: "0",
@@ -5008,7 +4855,7 @@ function AdminStudioMediaView(props) {
5008
4855
  }
5009
4856
 
5010
4857
  // src/admin/components/studio/AdminStudioMediaItemView.tsx
5011
- import { useEffect as useEffect16, useMemo as useMemo12, useState as useState17 } from "react";
4858
+ import { useEffect as useEffect16, useMemo as useMemo12, useState as useState18 } from "react";
5012
4859
  import { jsx as jsx28, jsxs as jsxs25 } from "react/jsx-runtime";
5013
4860
  var getPropString12 = (props, key, fallback) => {
5014
4861
  if (!props || typeof props !== "object") return fallback;
@@ -5040,11 +4887,11 @@ function AdminStudioMediaItemView(props) {
5040
4887
  const adminBasePath = useAdminBasePath();
5041
4888
  const mediaPath = resolveAdminPath(adminBasePath, "/media");
5042
4889
  const mediaIDFromParams = useMemo12(() => getParam2(props.params, "id"), [props.params]);
5043
- const [mediaID, setMediaID] = useState17(mediaIDFromParams);
5044
- const [doc, setDoc] = useState17(null);
5045
- const [loading, setLoading] = useState17(true);
5046
- const [error, setError] = useState17(null);
5047
- const [savedMessage, setSavedMessage] = useState17(null);
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);
5048
4895
  useEffect16(() => {
5049
4896
  if (mediaIDFromParams) {
5050
4897
  setMediaID(mediaIDFromParams);
@@ -5156,8 +5003,8 @@ function AdminStudioMediaItemView(props) {
5156
5003
 
5157
5004
  // src/admin/components/studio/AdminStudioFormsView.tsx
5158
5005
  import Link3 from "next/link";
5159
- import { useEffect as useEffect17, useMemo as useMemo13, useState as useState18 } from "react";
5160
- import { useAuth as useAuth6 } from "@payloadcms/ui";
5006
+ import { useEffect as useEffect17, useMemo as useMemo13, useState as useState19 } from "react";
5007
+ import { useAuth as useAuth5 } from "@payloadcms/ui";
5161
5008
  import { jsx as jsx29, jsxs as jsxs26 } from "react/jsx-runtime";
5162
5009
  var FORM_TONES = [
5163
5010
  {
@@ -5199,17 +5046,17 @@ var FORM_TONE_OVERRIDES = {
5199
5046
  var IDENTITY_KEYS = /* @__PURE__ */ new Set(["contactEmail", "email", "firstName", "lastName", "name"]);
5200
5047
  var RESPONSE_FIELD_PREVIEW_LIMIT = 3;
5201
5048
  var RESPONSE_SCROLL_THRESHOLD = 3;
5202
- var isAdmin3 = (user) => {
5049
+ var hasAdminAccess2 = (user) => {
5203
5050
  if (!user || typeof user !== "object") return false;
5204
5051
  const role = user.role;
5205
- return typeof role === "string" && role === "admin";
5052
+ return typeof role === "string" && (role === "admin" || role === "developer");
5206
5053
  };
5207
- var isEditor2 = (user) => {
5054
+ var isEditor = (user) => {
5208
5055
  if (!user || typeof user !== "object") return false;
5209
5056
  const role = user.role;
5210
5057
  return typeof role === "string" && role === "editor";
5211
5058
  };
5212
- var canReviewForms2 = (user) => isAdmin3(user) || isEditor2(user);
5059
+ var canReviewForms2 = (user) => hasAdminAccess2(user) || isEditor(user);
5213
5060
  var getPropString13 = (props, key, fallback) => {
5214
5061
  if (!props || typeof props !== "object") return fallback;
5215
5062
  const direct = props[key];
@@ -5375,25 +5222,21 @@ var renderEmptyMessage = (message) => /* @__PURE__ */ jsxs26("div", { className:
5375
5222
  /* @__PURE__ */ jsx29("span", { children: message })
5376
5223
  ] });
5377
5224
  function AdminStudioFormsView(props) {
5378
- const { user } = useAuth6();
5225
+ const { user } = useAuth5();
5379
5226
  const formsCollectionSlug = getPropString13(props, "formsCollectionSlug", "forms");
5380
5227
  const formSubmissionsCollectionSlug = getPropString13(
5381
5228
  props,
5382
5229
  "formSubmissionsCollectionSlug",
5383
5230
  "form-submissions"
5384
5231
  );
5385
- const formUploadsCollectionSlug = getPropString13(props, "formUploadsCollectionSlug", "form-uploads");
5386
5232
  const adminBasePath = useAdminBasePath();
5387
- const rawFormsPath = resolveAdminPath(adminBasePath, `/collections/${formsCollectionSlug}`);
5388
- const rawSubmissionsPath = resolveAdminPath(
5389
- adminBasePath,
5390
- `/collections/${formSubmissionsCollectionSlug}`
5391
- );
5392
- const rawUploadsPath = resolveAdminPath(adminBasePath, `/collections/${formUploadsCollectionSlug}`);
5393
- const [forms, setForms] = useState18([]);
5394
- const [submissions, setSubmissions] = useState18([]);
5395
- const [loading, setLoading] = useState18(true);
5396
- 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);
5397
5240
  useEffect17(() => {
5398
5241
  if (!canReviewForms2(user)) {
5399
5242
  return;
@@ -5549,7 +5392,7 @@ function AdminStudioFormsView(props) {
5549
5392
  Link3,
5550
5393
  {
5551
5394
  className: "orion-admin-action-button orion-admin-action-button--soft",
5552
- href: `${rawFormsPath}/${id}`,
5395
+ href: `${studioFormsPath}/${id}`,
5553
5396
  children: "Open Form"
5554
5397
  }
5555
5398
  )
@@ -5651,7 +5494,7 @@ function AdminStudioFormsView(props) {
5651
5494
  Link3,
5652
5495
  {
5653
5496
  className: "orion-admin-upload-chip",
5654
- href: `${rawUploadsPath}/${uploadID}`,
5497
+ href: `${studioUploadsPath}/${uploadID}`,
5655
5498
  children: uploadLabel
5656
5499
  },
5657
5500
  uploadID
@@ -5668,7 +5511,7 @@ function AdminStudioFormsView(props) {
5668
5511
  Link3,
5669
5512
  {
5670
5513
  className: "orion-admin-action-button orion-admin-action-button--ghost",
5671
- href: `${rawSubmissionsPath}/${submissionID}`,
5514
+ href: `${studioSubmissionsPath}/${submissionID}`,
5672
5515
  children: "Open"
5673
5516
  }
5674
5517
  )
@@ -5688,55 +5531,1681 @@ function AdminStudioFormsView(props) {
5688
5531
  ) });
5689
5532
  }
5690
5533
 
5691
- // src/admin/components/studio/AdminStudioToolsView.tsx
5692
- import { useEffect as useEffect18, useState as useState19 } from "react";
5693
- import { useAuth as useAuth7 } from "@payloadcms/ui";
5694
- import { jsx as jsx30, jsxs as jsxs27 } from "react/jsx-runtime";
5695
- var userRoles = ["admin", "client", "editor"];
5696
- var isAdmin4 = (user) => {
5697
- if (!user || typeof user !== "object") return false;
5698
- const role = user.role;
5699
- return typeof role === "string" && role === "admin";
5700
- };
5701
- var normalizeRole = (value) => userRoles.includes(value) ? value : "editor";
5702
- function AdminStudioToolsView(props) {
5703
- const { user } = useAuth7();
5704
- const adminBasePath = useAdminBasePath();
5705
- const [docs, setDocs] = useState19([]);
5706
- const [loading, setLoading] = useState19(true);
5707
- const [error, setError] = useState19(null);
5708
- const [savedMessage, setSavedMessage] = useState19(null);
5709
- const [createSubmitting, setCreateSubmitting] = useState19(false);
5710
- const [updatingUserID, setUpdatingUserID] = useState19(null);
5711
- if (!isAdmin4(user)) {
5712
- return /* @__PURE__ */ jsx30(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsx30(
5713
- AdminPage,
5714
- {
5715
- breadcrumbs: [
5716
- { label: "Dashboard", href: adminBasePath },
5717
- { label: "Admin Tools" }
5718
- ],
5719
- description: "You do not have access to this section.",
5720
- title: "Admin Tools",
5721
- children: /* @__PURE__ */ jsxs27("div", { className: "orion-admin-card", children: [
5722
- /* @__PURE__ */ jsx30("strong", { children: "Access denied" }),
5723
- /* @__PURE__ */ jsx30("span", { children: "This section is restricted to administrator accounts." })
5724
- ] })
5725
- }
5726
- ) });
5727
- }
5728
- const loadUsers = async () => {
5729
- setLoading(true);
5730
- setError(null);
5731
- try {
5732
- const params = new URLSearchParams({
5733
- depth: "0",
5734
- draft: "true",
5735
- limit: "200",
5736
- sort: "email"
5737
- });
5738
- const response = await fetch(`/api/users?${params.toString()}`, {
5739
- credentials: "include"
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]
5575
+ };
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.",
7189
+ title: "Admin Tools",
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." })
7193
+ ] })
7194
+ }
7195
+ ) });
7196
+ }
7197
+ const loadUsers = async () => {
7198
+ setLoading(true);
7199
+ setError(null);
7200
+ try {
7201
+ const params = new URLSearchParams({
7202
+ depth: "0",
7203
+ draft: "true",
7204
+ limit: "200",
7205
+ sort: "email"
7206
+ });
7207
+ const response = await fetch(`/api/users?${params.toString()}`, {
7208
+ credentials: "include"
5740
7209
  });
5741
7210
  if (!response.ok) {
5742
7211
  throw new Error(`Failed to load users (${response.status}).`);
@@ -5749,16 +7218,17 @@ function AdminStudioToolsView(props) {
5749
7218
  setLoading(false);
5750
7219
  }
5751
7220
  };
5752
- useEffect18(() => {
7221
+ useEffect21(() => {
5753
7222
  void loadUsers();
5754
7223
  }, []);
5755
7224
  const createUser = async (event) => {
5756
7225
  event.preventDefault();
7226
+ const form = event.currentTarget;
5757
7227
  setCreateSubmitting(true);
5758
7228
  setError(null);
5759
7229
  setSavedMessage(null);
5760
7230
  try {
5761
- const formData = new FormData(event.currentTarget);
7231
+ const formData = new FormData(form);
5762
7232
  const email = String(formData.get("email") || "").trim();
5763
7233
  const password = String(formData.get("password") || "");
5764
7234
  const fullName = String(formData.get("fullName") || "").trim();
@@ -5782,7 +7252,7 @@ function AdminStudioToolsView(props) {
5782
7252
  if (!response.ok) {
5783
7253
  throw new Error(`Failed to create user (${response.status}).`);
5784
7254
  }
5785
- event.currentTarget.reset();
7255
+ form.reset();
5786
7256
  await loadUsers();
5787
7257
  setSavedMessage("User created.");
5788
7258
  } catch (createError) {
@@ -5820,7 +7290,7 @@ function AdminStudioToolsView(props) {
5820
7290
  setUpdatingUserID(null);
5821
7291
  }
5822
7292
  };
5823
- return /* @__PURE__ */ jsx30(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs27(
7293
+ return /* @__PURE__ */ jsx33(StudioSectionLayout, { navProps: props, children: /* @__PURE__ */ jsxs30(
5824
7294
  AdminPage,
5825
7295
  {
5826
7296
  breadcrumbs: [
@@ -5830,53 +7300,44 @@ function AdminStudioToolsView(props) {
5830
7300
  description: "Manage users and fallback links to Payload native admin.",
5831
7301
  title: "Admin Tools",
5832
7302
  children: [
5833
- /* @__PURE__ */ jsx30("div", { className: "orion-admin-inline-actions", style: { marginBottom: "1rem" }, children: /* @__PURE__ */ jsx30("a", { className: "orion-admin-action-button", href: "/admin-core", target: "_blank", children: "Open Payload Core Admin" }) }),
5834
- error ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-error", style: { marginBottom: "1rem" }, children: error }) : null,
5835
- savedMessage ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-success", style: { marginBottom: "1rem" }, children: savedMessage }) : null,
5836
- /* @__PURE__ */ jsxs27("form", { className: "orion-admin-form", onSubmit: createUser, style: { marginBottom: "1rem" }, children: [
5837
- /* @__PURE__ */ jsx30("strong", { children: "Create User" }),
5838
- /* @__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: [
5839
7308
  "Email",
5840
- /* @__PURE__ */ jsx30("input", { name: "email", required: true, type: "email" })
7309
+ /* @__PURE__ */ jsx33("input", { name: "email", required: true, type: "email" })
5841
7310
  ] }),
5842
- /* @__PURE__ */ jsxs27("label", { children: [
7311
+ /* @__PURE__ */ jsxs30("label", { children: [
5843
7312
  "Full Name",
5844
- /* @__PURE__ */ jsx30("input", { name: "fullName", type: "text" })
7313
+ /* @__PURE__ */ jsx33("input", { name: "fullName", type: "text" })
5845
7314
  ] }),
5846
- /* @__PURE__ */ jsxs27("label", { children: [
7315
+ /* @__PURE__ */ jsxs30("label", { children: [
5847
7316
  "Password",
5848
- /* @__PURE__ */ jsx30("input", { name: "password", required: true, type: "password" })
7317
+ /* @__PURE__ */ jsx33("input", { name: "password", required: true, type: "password" })
5849
7318
  ] }),
5850
- /* @__PURE__ */ jsxs27("label", { children: [
7319
+ /* @__PURE__ */ jsxs30("label", { children: [
5851
7320
  "Role",
5852
- /* @__PURE__ */ jsxs27("select", { defaultValue: "editor", name: "role", children: [
5853
- /* @__PURE__ */ jsx30("option", { value: "admin", children: "admin" }),
5854
- /* @__PURE__ */ jsx30("option", { value: "editor", children: "editor" }),
5855
- /* @__PURE__ */ jsx30("option", { value: "client", children: "client" })
5856
- ] })
7321
+ /* @__PURE__ */ jsx33("select", { defaultValue: "editor", name: "role", children: userRoles.map((role) => /* @__PURE__ */ jsx33("option", { value: role, children: role }, role)) })
5857
7322
  ] }),
5858
- /* @__PURE__ */ jsx30("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
7323
+ /* @__PURE__ */ jsx33("button", { disabled: createSubmitting, type: "submit", children: createSubmitting ? "Creating..." : "Create User" })
5859
7324
  ] }),
5860
- loading ? /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: "Loading..." }) : null,
5861
- /* @__PURE__ */ jsx30("div", { className: "orion-admin-list", children: docs.map((doc) => {
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) => {
5862
7327
  const id = typeof doc.id === "string" || typeof doc.id === "number" ? String(doc.id) : "";
5863
7328
  if (!id) return null;
5864
7329
  const email = typeof doc.email === "string" ? doc.email : `user-${id}`;
5865
7330
  const fullName = typeof doc.fullName === "string" ? doc.fullName : "";
5866
7331
  const currentRole = typeof doc.role === "string" ? normalizeRole(doc.role) : "editor";
5867
- return /* @__PURE__ */ jsxs27("div", { className: "orion-admin-list-item", children: [
5868
- /* @__PURE__ */ jsxs27("div", { children: [
5869
- /* @__PURE__ */ jsx30("strong", { children: email }),
5870
- /* @__PURE__ */ jsx30("div", { className: "orion-admin-list-meta", children: fullName || "No full name set" })
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" })
5871
7336
  ] }),
5872
- /* @__PURE__ */ jsxs27("form", { className: "orion-admin-inline-actions", onSubmit: updateUserRole, children: [
5873
- /* @__PURE__ */ jsx30("input", { name: "id", type: "hidden", value: id }),
5874
- /* @__PURE__ */ jsxs27("select", { defaultValue: currentRole, name: "role", children: [
5875
- /* @__PURE__ */ jsx30("option", { value: "admin", children: "admin" }),
5876
- /* @__PURE__ */ jsx30("option", { value: "editor", children: "editor" }),
5877
- /* @__PURE__ */ jsx30("option", { value: "client", children: "client" })
5878
- ] }),
5879
- /* @__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" })
5880
7341
  ] })
5881
7342
  ] }, id);
5882
7343
  }) })
@@ -5887,14 +7348,14 @@ function AdminStudioToolsView(props) {
5887
7348
 
5888
7349
  // src/admin/components/studio/OpenInStudioMenuItem.tsx
5889
7350
  import { useDocumentInfo } from "@payloadcms/ui";
5890
- import { jsx as jsx31 } from "react/jsx-runtime";
7351
+ import { jsx as jsx34 } from "react/jsx-runtime";
5891
7352
  function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
5892
7353
  const documentInfo = useDocumentInfo();
5893
7354
  const id = documentInfo?.id;
5894
7355
  if (!id) {
5895
7356
  return null;
5896
7357
  }
5897
- return /* @__PURE__ */ jsx31(
7358
+ return /* @__PURE__ */ jsx34(
5898
7359
  "a",
5899
7360
  {
5900
7361
  href: `${pagesPathBase}/${id}`,
@@ -5913,19 +7374,19 @@ function OpenInStudioMenuItem({ pagesPathBase = "/pages" }) {
5913
7374
  }
5914
7375
 
5915
7376
  // src/admin/components/studio/PageEditRedirectToStudio.tsx
5916
- import { useEffect as useEffect19 } from "react";
7377
+ import { useEffect as useEffect22 } from "react";
5917
7378
  import { useDocumentInfo as useDocumentInfo2 } from "@payloadcms/ui";
5918
- import { jsx as jsx32, jsxs as jsxs28 } from "react/jsx-runtime";
7379
+ import { jsx as jsx35, jsxs as jsxs31 } from "react/jsx-runtime";
5919
7380
  function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
5920
7381
  const documentInfo = useDocumentInfo2();
5921
7382
  const id = documentInfo?.id;
5922
- useEffect19(() => {
7383
+ useEffect22(() => {
5923
7384
  if (!id) {
5924
7385
  return;
5925
7386
  }
5926
7387
  window.location.replace(`${pagesPathBase}/${id}`);
5927
7388
  }, [id, pagesPathBase]);
5928
- return /* @__PURE__ */ jsxs28(
7389
+ return /* @__PURE__ */ jsxs31(
5929
7390
  "div",
5930
7391
  {
5931
7392
  style: {
@@ -5937,18 +7398,61 @@ function PageEditRedirectToStudio({ pagesPathBase = "/pages" }) {
5937
7398
  minHeight: "50vh"
5938
7399
  },
5939
7400
  children: [
5940
- /* @__PURE__ */ jsx32("h2", { style: { margin: 0 }, children: "Opening Editor..." }),
5941
- /* @__PURE__ */ jsx32("p", { style: { color: "var(--theme-elevation-600)", margin: 0 }, children: "Redirecting to the custom page editor." }),
5942
- id ? /* @__PURE__ */ jsx32("a", { href: `${pagesPathBase}/${id}`, children: "Continue to Editor" }) : /* @__PURE__ */ jsx32("a", { href: pagesPathBase, children: "Open Pages" })
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 })
5943
7447
  ]
5944
7448
  }
5945
7449
  );
5946
7450
  }
5947
7451
 
5948
7452
  // src/admin/components/studio/StudioBackBreadcrumb.tsx
5949
- import { useEffect as useEffect20, useState as useState20 } from "react";
7453
+ import { useEffect as useEffect24, useState as useState24 } from "react";
5950
7454
  import { SetStepNav as SetStepNav5 } from "@payloadcms/ui";
5951
- import { jsx as jsx33 } from "react/jsx-runtime";
7455
+ import { jsx as jsx37 } from "react/jsx-runtime";
5952
7456
  var toTitle = (slug) => slug.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
5953
7457
  var buildNav = (pathname, adminBasePath) => {
5954
7458
  if (pathname.includes("/globals/")) {
@@ -5993,8 +7497,8 @@ var buildNav = (pathname, adminBasePath) => {
5993
7497
  };
5994
7498
  function StudioBackBreadcrumb() {
5995
7499
  const adminBasePath = useAdminBasePath();
5996
- const [pathname, setPathname] = useState20("");
5997
- useEffect20(() => {
7500
+ const [pathname, setPathname] = useState24("");
7501
+ useEffect24(() => {
5998
7502
  const update = () => setPathname(window.location.pathname);
5999
7503
  update();
6000
7504
  window.addEventListener("popstate", update);
@@ -6002,13 +7506,13 @@ function StudioBackBreadcrumb() {
6002
7506
  }, []);
6003
7507
  const nav = buildNav(pathname, adminBasePath);
6004
7508
  if (!nav) return null;
6005
- return /* @__PURE__ */ jsx33(SetStepNav5, { nav });
7509
+ return /* @__PURE__ */ jsx37(SetStepNav5, { nav });
6006
7510
  }
6007
7511
 
6008
7512
  // src/admin/components/studio/StudioContactFormRedirect.tsx
6009
- import { useEffect as useEffect21 } from "react";
6010
- import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
6011
- var getPropString14 = (props, key, fallback) => {
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) => {
6012
7516
  if (!props || typeof props !== "object") return fallback;
6013
7517
  const direct = props[key];
6014
7518
  if (typeof direct === "string" && direct.length > 0) return direct;
@@ -6021,13 +7525,13 @@ var getPropString14 = (props, key, fallback) => {
6021
7525
  };
6022
7526
  function StudioContactFormRedirect(props) {
6023
7527
  const adminBasePath = useAdminBasePath();
6024
- const studioContactFormPath = getPropString14(props, "studioContactFormPath", "/contact-form");
7528
+ const studioContactFormPath = getPropString15(props, "studioContactFormPath", "/contact-form");
6025
7529
  const targetPath = resolveAdminPath(adminBasePath, studioContactFormPath);
6026
- useEffect21(() => {
7530
+ useEffect25(() => {
6027
7531
  if (window.location.pathname === targetPath) return;
6028
7532
  window.location.replace(targetPath);
6029
7533
  }, [targetPath]);
6030
- return /* @__PURE__ */ jsxs29(
7534
+ return /* @__PURE__ */ jsxs33(
6031
7535
  "div",
6032
7536
  {
6033
7537
  style: {
@@ -6040,8 +7544,8 @@ function StudioContactFormRedirect(props) {
6040
7544
  minHeight: "40vh"
6041
7545
  },
6042
7546
  children: [
6043
- /* @__PURE__ */ jsx34("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
6044
- /* @__PURE__ */ jsx34("a", { href: targetPath, children: "Continue" })
7547
+ /* @__PURE__ */ jsx38("h2", { style: { margin: 0 }, children: "Opening Contact Form Editor..." }),
7548
+ /* @__PURE__ */ jsx38("a", { href: targetPath, children: "Continue" })
6045
7549
  ]
6046
7550
  }
6047
7551
  );
@@ -6052,6 +7556,9 @@ export {
6052
7556
  AdminStudioContactFormView,
6053
7557
  AdminStudioDashboard,
6054
7558
  AdminStudioFooterGlobalView,
7559
+ AdminStudioFormDetailView,
7560
+ AdminStudioFormSubmissionView,
7561
+ AdminStudioFormUploadView,
6055
7562
  AdminStudioFormsView,
6056
7563
  AdminStudioGlobalsView,
6057
7564
  AdminStudioHeaderGlobalView,
@@ -6077,6 +7584,7 @@ export {
6077
7584
  StatusBadge,
6078
7585
  StudioBackBreadcrumb,
6079
7586
  StudioContactFormRedirect,
7587
+ StudioDocumentRedirect,
6080
7588
  StudioSectionLayout,
6081
7589
  ThemeProvider,
6082
7590
  ThemeSwitcher,